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);
 }
  private void generateSetEntityId(
      XMethodVisitor mv,
      Method method,
      String objectModelProxyClassName,
      Class<?> objectModelClass,
      HibernateObjectModelMetadata jpaObjectModelMetadata) {

    final JPAScalarProperty entityIdProperty = jpaObjectModelMetadata.getEntityIdProperty();
    this.generateLazyInitializer(mv, objectModelProxyClassName);
    mv.visitBox(
        entityIdProperty.getReturnClass(),
        new Action<XMethodVisitor>() {
          @Override
          public void run(XMethodVisitor mv) {
            mv.visitVarInsn(ASM.getLoadCode(entityIdProperty.getReturnClass()), 1);
          }
        });
    mv.visitMethodInsn(
        Opcodes.INVOKEINTERFACE,
        ASM.getInternalName(LazyInitializer.class),
        "setIdentifier",
        "(Ljava/io/Serializable;)V",
        true);
    mv.visitInsn(Opcodes.RETURN);
  }
  private void generateGetEntityId(
      XMethodVisitor mv,
      Method method,
      String objectModelProxyClassName,
      Class<?> objectModelClass,
      HibernateObjectModelMetadata jpaObjectModelMetadata) {
    final JPAScalarProperty entityIdProperty = jpaObjectModelMetadata.getDeclaredEntityIdProperty();

    this.generateLazyInitializer(mv, objectModelProxyClassName);
    mv.visitMethodInsn(
        Opcodes.INVOKEINTERFACE,
        ASM.getInternalName(LazyInitializer.class),
        "getIdentifier",
        "()Ljava/io/Serializable;",
        true);
    if (entityIdProperty.getReturnClass().isPrimitive()) {
      mv.visitUnbox(entityIdProperty.getReturnClass(), XMethodVisitor.JVM_PRIMTIVIE_DEFAULT_VALUE);
    } else {
      mv.visitTypeInsn(Opcodes.CHECKCAST, ASM.getInternalName(entityIdProperty.getReturnClass()));
    }
    mv.visitInsn(ASM.getReturnCode(entityIdProperty.getReturnClass()));
  }
  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;
  }