private void generateFreezeSclarAndUnfreezeScalarCode( XMethodVisitor mv, Method method, String objectModelProxyClassName, Class<?> objectModelClass, HibernateObjectModelMetadata jpaObjectModelMetadata, boolean freeze) { final JPAScalarProperty entityIdProperty = jpaObjectModelMetadata.getEntityIdProperty(); Label invokeImplemenationLabel = new Label(); mv.visitVarInsn(Opcodes.ILOAD, 1); mv.visitLdcInsn(entityIdProperty.getId()); mv.visitJumpInsn(Opcodes.IF_ICMPNE, invokeImplemenationLabel); this.generateLazyInitializer(mv, objectModelProxyClassName); mv.visitVarInsn(Opcodes.ALOAD, 2); mv.visitMethodInsn( Opcodes.INVOKEINTERFACE, ASM.getInternalName(FrozenLazyInitializer.class), freeze ? "freezeIdentifier" : "unfreezeIdentifier", '(' + ASM.getDescriptor(FrozenContext.class) + ")V", true); mv.visitInsn(Opcodes.RETURN); mv.visitLabel(invokeImplemenationLabel); this.generateDefaultProxyMethodCode( mv, method, objectModelProxyClassName, objectModelClass, jpaObjectModelMetadata, true); }
@Override protected void generateCreateInsns(MethodVisitor mv) { if (this.getObjectModelMetadata().getMode() == ObjectModelMode.REFERENCE) { Label defaultImplLabel = new Label(); Class<?> objectModelProxyClass = HibernateObjectModelFactoryProvider.this.generateObjectModelProxy( this.getObjectModelMetadata().getObjectModelClass()); mv.visitVarInsn(Opcodes.ALOAD, 1); mv.visitTypeInsn(Opcodes.INSTANCEOF, HIBERNATE_PROXY_INTERNAL_NAME); mv.visitJumpInsn(Opcodes.IFEQ, defaultImplLabel); mv.visitTypeInsn(Opcodes.NEW, objectModelProxyClass.getName().replace('.', '/')); mv.visitInsn(Opcodes.DUP); mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitVarInsn(Opcodes.ALOAD, 1); mv.visitTypeInsn(Opcodes.CHECKCAST, HIBERNATE_PROXY_INTERNAL_NAME); mv.visitMethodInsn( Opcodes.INVOKESPECIAL, objectModelProxyClass.getName().replace('.', '/'), "<init>", '(' + ASM.getDescriptor(ObjectModelFactory.class) + HIBERNATE_PROXY_DESC + ")V", false); mv.visitInsn(Opcodes.ARETURN); mv.visitLabel(defaultImplLabel); } super.generateCreateInsns(mv); }
private void generateLazyInitializer(XMethodVisitor mv, String objectModelProxyClassName) { mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitFieldInsn( Opcodes.GETFIELD, objectModelProxyClassName.replace('.', '/'), HIBERNATE_PROXY_OWNER, HIBERNATE_PROXY_DESC); mv.visitMethodInsn( Opcodes.INVOKESTATIC, ASM.getInternalName(FrozenLazyInitializerImpl.class), "getFrozenLazyInitializer", '(' + ASM.getDescriptor(HibernateProxy.class) + ')' + ASM.getDescriptor(FrozenLazyInitializer.class), false); }
@Override protected void generateGetInsns(MethodVisitor mv) { Label defaultImplLabel = new Label(); mv.visitVarInsn(Opcodes.ALOAD, 1); mv.visitTypeInsn(Opcodes.INSTANCEOF, HIBERNATE_PROXY_INTERNAL_NAME); mv.visitJumpInsn(Opcodes.IFEQ, defaultImplLabel); mv.visitVarInsn(Opcodes.ALOAD, 1); mv.visitTypeInsn(Opcodes.CHECKCAST, HIBERNATE_PROXY_INTERNAL_NAME); mv.visitMethodInsn( Opcodes.INVOKESTATIC, ASM.getInternalName(FrozenLazyInitializerImpl.class), "getFrozenLazyInitializer", '(' + ASM.getDescriptor(HibernateProxy.class) + ')' + ASM.getDescriptor(FrozenLazyInitializer.class), false); mv.visitInsn(Opcodes.POP); mv.visitLabel(defaultImplLabel); super.generateGetInsns(mv); }
// TODO: refactor it into the nested class private void generateDefaultProxyMethodCode( XMethodVisitor mv, Method method, final String objectModelProxyClassName, Class<?> objectModelClass, HibernateObjectModelMetadata jpaObjectModelMetadata, boolean generateReturn) { final String desc = ASM.getDescriptor(method); visitGetObjectModel( mv, jpaObjectModelMetadata, new Action<MethodVisitor>() { @Override public void run(MethodVisitor mv) { mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitFieldInsn( Opcodes.GETFIELD, objectModelProxyClassName.replace('.', '/'), HIBERNATE_PROXY_OWNER, HIBERNATE_PROXY_DESC); mv.visitMethodInsn( Opcodes.INVOKEINTERFACE, HIBERNATE_PROXY_INTERNAL_NAME, "getHibernateLazyInitializer", "()" + ASM.getDescriptor(LazyInitializer.class), true); mv.visitMethodInsn( Opcodes.INVOKEINTERFACE, LazyInitializer.class.getName().replace('.', '/'), "getImplementation", "()Ljava/lang/Object;", true); } }); String interfaceInternalName = method.getDeclaringClass() == ObjectModel.class ? ASM.getInternalName(ObjectModel.class) : ASM.getInternalName(objectModelClass); mv.visitTypeInsn(Opcodes.CHECKCAST, interfaceInternalName); int slot = 1; for (Class<?> parameterClass : method.getParameterTypes()) { mv.visitVarInsn(ASM.getLoadCode(parameterClass), slot); slot += ASM.getSlotCount(parameterClass); } mv.visitMethodInsn( Opcodes.INVOKEINTERFACE, interfaceInternalName, method.getName(), desc, true); if (generateReturn) { mv.visitInsn(ASM.getReturnCode(method.getReturnType())); } }
private void generateToString(ClassVisitor cv) { MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null); mv.visitCode(); mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitMethodInsn( Opcodes.INVOKESTATIC, ASM.getInternalName(AppendingContext.class), "toString", '(' + ASM.getDescriptor(ObjectModel.class) + ")Ljava/lang/String;", false); mv.visitInsn(Opcodes.ARETURN); mv.visitMaxs(0, 0); mv.visitEnd(); }
private void generateAddScalarListenerAndRemoveScalarListenerCode( XMethodVisitor mv, Method method, String objectModelProxyClassName, Class<?> objectModelClass, HibernateObjectModelMetadata jpaObjectModelMetadata, boolean add) { this.generateLazyInitializer(mv, objectModelProxyClassName); mv.visitVarInsn(Opcodes.ALOAD, 1); mv.visitMethodInsn( Opcodes.INVOKEINTERFACE, ASM.getInternalName(FrozenLazyInitializer.class), add ? "addScalarListener" : "removeScalarListener", '(' + ASM.getDescriptor(ScalarListener.class) + ")V", true); mv.visitInsn(Opcodes.RETURN); }
private void generateAppendTo(ClassVisitor cv, final String objectModelProxyClassName) { XMethodVisitor mv = ASM.visitMethod( cv, Opcodes.ACC_PUBLIC, "appendTo", '(' + ASM.getDescriptor(AppendingContext.class) + ")V", null, null); mv.visitCode(); final int lazyInitializerIndex = mv.aSlot("lazyInitializer"); final Label needAppendLabel = new Label(); final Label isInitializedLabel = new Label(); final Label afterAppendToLabel = new Label(); mv.visitVarInsn(Opcodes.ALOAD, 1); mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL, ASM.getInternalName(AppendingContext.class), "enter", '(' + ASM.getDescriptor(ObjectModel.class) + ")Z", false); mv.visitJumpInsn(Opcodes.IFNE, needAppendLabel); mv.visitInsn(Opcodes.RETURN); mv.visitLabel(needAppendLabel); Action<MethodVisitor> tryAction = new Action<MethodVisitor>() { @Override public void run(MethodVisitor mv) { mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitFieldInsn( Opcodes.GETFIELD, objectModelProxyClassName.replace('.', '/'), HIBERNATE_PROXY_OWNER, HIBERNATE_PROXY_DESC); mv.visitMethodInsn( Opcodes.INVOKEINTERFACE, HIBERNATE_PROXY_INTERNAL_NAME, "getHibernateLazyInitializer", "()" + ASM.getDescriptor(LazyInitializer.class), true); mv.visitVarInsn(Opcodes.ASTORE, lazyInitializerIndex); mv.visitVarInsn(Opcodes.ALOAD, lazyInitializerIndex); mv.visitMethodInsn( Opcodes.INVOKEINTERFACE, ASM.getInternalName(LazyInitializer.class), "isUninitialized", "()Z", true); mv.visitJumpInsn(Opcodes.IFEQ, isInitializedLabel); mv.visitVarInsn(Opcodes.ALOAD, 1); mv.visitLdcInsn("$unloadedProxy()"); mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL, ASM.getInternalName(AppendingContext.class), "appendValue", "(Ljava/lang/String;)V", false); mv.visitJumpInsn(Opcodes.GOTO, afterAppendToLabel); mv.visitLabel(isInitializedLabel); mv.visitFieldInsn( Opcodes.GETSTATIC, objectModelProxyClassName.replace('.', '/'), OBJECT_MODEL_IMPL_FACTORY, ASM.getDescriptor(ObjectModelFactory.class)); mv.visitVarInsn(Opcodes.ALOAD, lazyInitializerIndex); mv.visitMethodInsn( Opcodes.INVOKEINTERFACE, ASM.getInternalName(LazyInitializer.class), "getImplementation", "()Ljava/lang/Object;", true); mv.visitMethodInsn( Opcodes.INVOKEINTERFACE, ASM.getInternalName(ObjectModelFactory.class), "get", "(Ljava/lang/Object;)Ljava/lang/Object;", true); mv.visitTypeInsn(Opcodes.CHECKCAST, ASM.getInternalName(ObjectModelAppender.class)); mv.visitVarInsn(Opcodes.ALOAD, 1); mv.visitMethodInsn( Opcodes.INVOKEINTERFACE, ASM.getInternalName(ObjectModelAppender.class), "appendTo", '(' + ASM.getDescriptor(AppendingContext.class) + ")V", true); mv.visitLabel(afterAppendToLabel); } }; Action<MethodVisitor> finallyAction = new Action<MethodVisitor>() { @Override public void run(MethodVisitor mv) { mv.visitVarInsn(Opcodes.ALOAD, 1); mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL, ASM.getInternalName(AppendingContext.class), "exit", '(' + ASM.getDescriptor(ObjectModel.class) + ")V", false); } }; mv.visitTryFinally(tryAction, finallyAction); mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); }
private int generateProxyMethodForReferenceMode( ClassVisitor cv, Method method, final String objectModelProxyClassName, Class<?> objectModelClass, HibernateObjectModelMetadata jpaObjectModelMetadata) { int retval; final JPAScalarProperty entityIdProperty = jpaObjectModelMetadata.getEntityIdProperty(); final String desc = ASM.getDescriptor(method); XMethodVisitor mv = ASM.visitMethod(cv, Opcodes.ACC_PUBLIC, method.getName(), desc, null, null); mv.visitCode(); if (method.getName().equals(entityIdProperty.getGetterName()) && method.getParameterTypes().length == 0 && method.getReturnType() == entityIdProperty.getReturnClass()) { this.generateGetEntityId( mv, method, objectModelProxyClassName, objectModelClass, jpaObjectModelMetadata); retval = 1 << 0; } else if (method.getName().equals(entityIdProperty.getSetterName()) && Arrays.equals( method.getParameterTypes(), new Class[] {entityIdProperty.getReturnClass()}) && method.getReturnType() == void.class) { this.generateSetEntityId( mv, method, objectModelProxyClassName, objectModelClass, jpaObjectModelMetadata); retval = 1 << 1; } else if (method.getName().equals("getScalar") && Arrays.equals(method.getParameterTypes(), new Class[] {int.class}) && method.getReturnType() == Object.class) { Label invokeImplemenationLabel = new Label(); mv.visitVarInsn(Opcodes.ILOAD, 1); mv.visitLdcInsn(entityIdProperty.getId()); mv.visitJumpInsn(Opcodes.IF_ICMPNE, invokeImplemenationLabel); mv.visitBox( entityIdProperty.getReturnClass(), new Action<XMethodVisitor>() { @Override public void run(XMethodVisitor mv) { mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL, objectModelProxyClassName.replace('.', '/'), entityIdProperty.getGetterName(), "()" + ASM.getDescriptor(entityIdProperty.getReturnClass()), false); } }); mv.visitInsn(Opcodes.ARETURN); mv.visitLabel(invokeImplemenationLabel); this.generateDefaultProxyMethodCode( mv, method, objectModelProxyClassName, objectModelClass, jpaObjectModelMetadata, true); retval = 1 << 2; } else if (method.getName().equals("setScalar") && Arrays.equals(method.getParameterTypes(), new Class[] {int.class, Object.class}) && method.getReturnType() == void.class) { Label invokeImplemenationLabel = new Label(); mv.visitVarInsn(Opcodes.ILOAD, 1); mv.visitLdcInsn(entityIdProperty.getId()); mv.visitJumpInsn(Opcodes.IF_ICMPNE, invokeImplemenationLabel); mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitVarInsn(Opcodes.ALOAD, 2); if (entityIdProperty.getReturnClass().isPrimitive()) { mv.visitUnbox( entityIdProperty.getReturnClass(), XMethodVisitor.JVM_PRIMTIVIE_DEFAULT_VALUE); } else { mv.visitTypeInsn(Opcodes.CHECKCAST, ASM.getInternalName(entityIdProperty.getReturnClass())); } mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL, objectModelProxyClassName.replace('.', '/'), entityIdProperty.getSetterName(), '(' + ASM.getDescriptor(entityIdProperty.getReturnClass()) + ")V", false); mv.visitInsn(Opcodes.RETURN); mv.visitLabel(invokeImplemenationLabel); this.generateDefaultProxyMethodCode( mv, method, objectModelProxyClassName, objectModelClass, jpaObjectModelMetadata, true); retval = 1 << 3; } else if (method.getName().equals("freezeScalar") && Arrays.equals(method.getParameterTypes(), new Class[] {int.class, FrozenContext.class}) && method.getReturnType() == void.class) { this.generateFreezeSclarAndUnfreezeScalarCode( mv, method, objectModelProxyClassName, objectModelClass, jpaObjectModelMetadata, true); retval = 1 << 4; } else if (method.getName().equals("unfreezeScalar") && Arrays.equals(method.getParameterTypes(), new Class[] {int.class, FrozenContext.class}) && method.getReturnType() == void.class) { this.generateFreezeSclarAndUnfreezeScalarCode( mv, method, objectModelProxyClassName, objectModelClass, jpaObjectModelMetadata, false); retval = 1 << 5; } else if (method.getName().equals("addScalarListener") && Arrays.equals(method.getParameterTypes(), new Class[] {ScalarListener.class}) && method.getReturnType() == void.class) { this.generateAddScalarListenerAndRemoveScalarListenerCode( mv, method, objectModelProxyClassName, objectModelClass, jpaObjectModelMetadata, true); retval = 1 << 6; } else if (method.getName().equals("removeScalarListener") && Arrays.equals(method.getParameterTypes(), new Class[] {ScalarListener.class}) && method.getReturnType() == void.class) { this.generateAddScalarListenerAndRemoveScalarListenerCode( mv, method, objectModelProxyClassName, objectModelClass, jpaObjectModelMetadata, false); retval = 1 << 7; } else { this.generateDefaultProxyMethodCode( mv, method, objectModelProxyClassName, objectModelClass, jpaObjectModelMetadata, true); retval = 0; } mv.visitMaxs(0, 0); mv.visitEnd(); return retval; }
private void generateObjectModelProxy( Class<?> objectModelClass, String objectModelProxyClassName, ClassVisitor cv) { Class<?> ownerClass = objectModelClass.getDeclaringClass(); HibernateObjectModelMetadata hibernateObjectModelMetadata = this.getMetadataFactory().getMetadata(ownerClass); String objectModelInternalName = objectModelClass.getName().replace('.', '/'); String objectModelProxyInternalName = objectModelProxyClassName.replace('.', '/'); cv.visit( Opcodes.V1_7, Opcodes.ACC_PUBLIC, objectModelProxyInternalName, null, "java/lang/Object", new String[] { objectModelInternalName, ASM.getInternalName(ObjectModel.class), ASM.getInternalName(ObjectModelAppender.class) }); cv.visitField( Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, OBJECT_MODEL_IMPL_FACTORY, ASM.getDescriptor(ObjectModelFactory.class), null, null) .visitEnd(); cv.visitField(Opcodes.ACC_PRIVATE, HIBERNATE_PROXY_OWNER, HIBERNATE_PROXY_DESC, null, null) .visitEnd(); XMethodVisitor mv; mv = ASM.visitMethod( cv, Opcodes.ACC_PUBLIC, "<init>", '(' + ASM.getDescriptor(ObjectModelFactory.class) + HIBERNATE_PROXY_DESC + ")V", null, null); mv.visitCode(); mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); mv.visitLdcInsn(Type.getType(objectModelClass)); mv.visitMethodInsn( Opcodes.INVOKESTATIC, ASM.getInternalName(ObjectModelFactoryFactory.class), "factoryOf", "(Ljava/lang/Class;)" + ASM.getDescriptor(ObjectModelFactory.class), false); mv.visitFieldInsn( Opcodes.PUTSTATIC, objectModelProxyInternalName, OBJECT_MODEL_IMPL_FACTORY, ASM.getDescriptor(ObjectModelFactory.class)); mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitVarInsn(Opcodes.ALOAD, 2); mv.visitFieldInsn( Opcodes.PUTFIELD, objectModelProxyInternalName, HIBERNATE_PROXY_OWNER, HIBERNATE_PROXY_DESC); mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); int gernatedMask = 0; for (Method method : objectModelClass.getMethods()) { gernatedMask |= this.generateProxyMethodForReferenceMode( cv, method, objectModelProxyInternalName, objectModelClass, hibernateObjectModelMetadata); } if (!ObjectModel.class.isAssignableFrom(objectModelClass)) { for (Method method : ObjectModel.class.getMethods()) { gernatedMask |= this.generateProxyMethodForReferenceMode( cv, method, objectModelProxyInternalName, objectModelClass, hibernateObjectModelMetadata); } } if (gernatedMask != (1 << 8) - (hibernateObjectModelMetadata.getDeclaredEntityIdProperty() == null ? 4 : 1)) { throw new AssertionError(); } mv = ASM.visitMethod( cv, Opcodes.ACC_PROTECTED, "writeReplace", "()Ljava/lang/Object;", null, new String[] {ASM.getInternalName(ObjectStreamException.class)}); mv.visitCode(); mv.visitTypeInsn( Opcodes.NEW, ASM.getInternalName(HibernateObjectModelProxyWritingReplacment.class)); mv.visitInsn(Opcodes.DUP); mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitMethodInsn( Opcodes.INVOKESPECIAL, ASM.getInternalName(HibernateObjectModelProxyWritingReplacment.class), "<init>", '(' + ASM.getDescriptor(ObjectModel.class) + ")V", false); mv.visitInsn(Opcodes.ARETURN); mv.visitMaxs(0, 0); mv.visitEnd(); this.generateAppendTo(cv, objectModelProxyClassName); this.generateToString(cv); cv.visitEnd(); }