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 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();
  }