public void addGetter(MetaBeanProperty property) throws Exception {
      MetaMethod getter = property.getGetter();

      // GENERATE private boolean <prop>Set;

      String flagName = String.format("%sSet", property.getName());
      visitor.visitField(
          Opcodes.ACC_PRIVATE, flagName, Type.BOOLEAN_TYPE.getDescriptor(), null, null);

      addConventionGetter(getter.getName(), flagName, property);

      String getterName = getter.getName();
      Class<?> returnType = getter.getReturnType();

      // If it's a boolean property, there can be get or is type variants.
      // If this class has both, decorate both.
      if (returnType.equals(Boolean.TYPE)) {
        boolean getterIsIsMethod = getterName.startsWith("is");
        String propertyNameComponent = getterName.substring(getterIsIsMethod ? 2 : 3);
        String alternativeGetterName =
            String.format("%s%s", getterIsIsMethod ? "get" : "is", propertyNameComponent);

        try {
          type.getMethod(alternativeGetterName);
          addConventionGetter(alternativeGetterName, flagName, property);
        } catch (NoSuchMethodException e) {
          // ignore, no method to override
        }
      }
    }
    public void mixInConventionAware() throws Exception {
      // GENERATE private ConventionMapping mapping = new ConventionAwareHelper(this,
      // getConvention())

      final String mappingFieldSignature =
          "L" + ConventionMapping.class.getName().replaceAll("\\.", "/") + ";";
      final String getConventionDesc = Type.getMethodDescriptor(conventionType, new Type[0]);

      visitor.visitField(Opcodes.ACC_PRIVATE, "mapping", mappingFieldSignature, null, null);

      initConventionAwareHelper =
          new MethodCodeBody() {
            public void add(MethodVisitor visitor) throws Exception {
              Type helperType = Type.getType(ConventionAwareHelper.class);

              // GENERATE mapping = new ConventionAwareHelper(this, getConvention())
              visitor.visitVarInsn(Opcodes.ALOAD, 0);

              visitor.visitTypeInsn(Opcodes.NEW, helperType.getInternalName());
              visitor.visitInsn(Opcodes.DUP);
              visitor.visitVarInsn(Opcodes.ALOAD, 0);

              // GENERATE getConvention()

              visitor.visitVarInsn(Opcodes.ALOAD, 0);
              visitor.visitMethodInsn(
                  Opcodes.INVOKEVIRTUAL,
                  generatedType.getInternalName(),
                  "getConvention",
                  getConventionDesc);

              // END

              String constructorDesc =
                  Type.getMethodDescriptor(
                      Type.VOID_TYPE, new Type[] {conventionAwareType, conventionType});
              visitor.visitMethodInsn(
                  Opcodes.INVOKESPECIAL, helperType.getInternalName(), "<init>", constructorDesc);

              visitor.visitFieldInsn(
                  Opcodes.PUTFIELD,
                  generatedType.getInternalName(),
                  "mapping",
                  mappingFieldSignature);

              // END
            }
          };

      // END

      // GENERATE public ConventionMapping getConventionMapping() { if (mapping != null) { return
      // mapping; } else { return new ConventionAwareHelper(this); } }
      // the null check is for when getConventionMapping() is called by a superclass constructor (eg
      // when the constructor calls a getter method)

      addGetter(
          IConventionAware.class.getDeclaredMethod("getConventionMapping"),
          new MethodCodeBody() {
            public void add(MethodVisitor visitor) {
              // GENERATE if (mapping != null) {... }
              visitor.visitVarInsn(Opcodes.ALOAD, 0);
              visitor.visitFieldInsn(
                  Opcodes.GETFIELD,
                  generatedType.getInternalName(),
                  "mapping",
                  mappingFieldSignature);
              visitor.visitInsn(Opcodes.DUP);
              Label nullBranch = new Label();
              visitor.visitJumpInsn(Opcodes.IFNULL, nullBranch);
              visitor.visitInsn(Opcodes.ARETURN);
              // GENERATE else { return new ConventionAwareHelper(this); }
              visitor.visitLabel(nullBranch);
              Type conventionAwareHelperType = Type.getType(ConventionAwareHelper.class);
              String constructorDesc =
                  Type.getMethodDescriptor(
                      Type.VOID_TYPE, new Type[] {Type.getType(IConventionAware.class)});
              visitor.visitTypeInsn(Opcodes.NEW, conventionAwareHelperType.getInternalName());
              visitor.visitInsn(Opcodes.DUP);
              visitor.visitVarInsn(Opcodes.ALOAD, 0);
              visitor.visitMethodInsn(
                  Opcodes.INVOKESPECIAL,
                  conventionAwareHelperType.getInternalName(),
                  "<init>",
                  constructorDesc);
              visitor.visitInsn(Opcodes.ARETURN);
            }
          });
    }
    public void mixInGroovyObject() throws Exception {

      // GENERATE private MetaClass metaClass =
      // GroovySystem.getMetaClassRegistry().getMetaClass(getClass())

      final String metaClassFieldSignature =
          "L" + MetaClass.class.getName().replaceAll("\\.", "/") + ";";
      visitor.visitField(Opcodes.ACC_PRIVATE, "metaClass", metaClassFieldSignature, null, null);

      initMetaClass =
          new MethodCodeBody() {
            public void add(MethodVisitor visitor) throws Exception {
              visitor.visitVarInsn(Opcodes.ALOAD, 0);

              // GroovySystem.getMetaClassRegistry()
              String getMetaClassRegistryDesc =
                  Type.getMethodDescriptor(
                      GroovySystem.class.getDeclaredMethod("getMetaClassRegistry"));
              visitor.visitMethodInsn(
                  Opcodes.INVOKESTATIC,
                  Type.getType(GroovySystem.class).getInternalName(),
                  "getMetaClassRegistry",
                  getMetaClassRegistryDesc);

              // this.getClass()
              visitor.visitVarInsn(Opcodes.ALOAD, 0);
              String getClassDesc =
                  Type.getMethodDescriptor(Object.class.getDeclaredMethod("getClass"));
              visitor.visitMethodInsn(
                  Opcodes.INVOKEVIRTUAL,
                  Type.getType(Object.class).getInternalName(),
                  "getClass",
                  getClassDesc);

              // getMetaClass(..)
              String getMetaClassDesc =
                  Type.getMethodDescriptor(
                      MetaClassRegistry.class.getDeclaredMethod("getMetaClass", Class.class));
              visitor.visitMethodInsn(
                  Opcodes.INVOKEINTERFACE,
                  Type.getType(MetaClassRegistry.class).getInternalName(),
                  "getMetaClass",
                  getMetaClassDesc);

              visitor.visitFieldInsn(
                  Opcodes.PUTFIELD,
                  generatedType.getInternalName(),
                  "metaClass",
                  metaClassFieldSignature);
            }
          };

      // GENERATE public MetaClass getMetaClass() { return metaClass }

      addGetter(
          GroovyObject.class.getDeclaredMethod("getMetaClass"),
          new MethodCodeBody() {
            public void add(MethodVisitor visitor) throws Exception {
              visitor.visitVarInsn(Opcodes.ALOAD, 0);
              visitor.visitFieldInsn(
                  Opcodes.GETFIELD,
                  generatedType.getInternalName(),
                  "metaClass",
                  metaClassFieldSignature);
            }
          });

      // GENERATE public void setMetaClass(MetaClass class) { this.metaClass = class; }

      addSetter(
          GroovyObject.class.getDeclaredMethod("setMetaClass", MetaClass.class),
          new MethodCodeBody() {
            public void add(MethodVisitor visitor) throws Exception {
              visitor.visitVarInsn(Opcodes.ALOAD, 0);
              visitor.visitVarInsn(Opcodes.ALOAD, 1);
              visitor.visitFieldInsn(
                  Opcodes.PUTFIELD,
                  generatedType.getInternalName(),
                  "metaClass",
                  metaClassFieldSignature);
            }
          });
    }
    public void mixInDynamicAware() throws Exception {
      final Type helperType = Type.getType(MixInExtensibleDynamicObject.class);

      // GENERATE private MixInExtensibleDynamicObject dynamicObjectHelper = new
      // MixInExtensibleDynamicObject(this, super.getAsDynamicObject())

      final String fieldSignature =
          "L" + MixInExtensibleDynamicObject.class.getName().replaceAll("\\.", "/") + ";";
      visitor.visitField(Opcodes.ACC_PRIVATE, "dynamicObjectHelper", fieldSignature, null, null);
      initDynamicObjectHelper =
          new MethodCodeBody() {
            public void add(MethodVisitor visitor) throws Exception {
              String helperTypeConstructorDesc =
                  Type.getMethodDescriptor(
                      Type.VOID_TYPE, new Type[] {Type.getType(Object.class), dynamicObjectType});

              // GENERATE dynamicObjectHelper = new MixInExtensibleDynamicObject(this,
              // super.getAsDynamicObject())

              visitor.visitVarInsn(Opcodes.ALOAD, 0);

              // GENERATE new MixInExtensibleDynamicObject(this, super.getAsDynamicObject())
              visitor.visitTypeInsn(Opcodes.NEW, helperType.getInternalName());
              visitor.visitInsn(Opcodes.DUP);

              visitor.visitVarInsn(Opcodes.ALOAD, 0);

              boolean useInheritedDynamicObject =
                  GroovySystem.getMetaClassRegistry()
                          .getMetaClass(type)
                          .pickMethod("getAsDynamicObject", new Class[0])
                      != null;

              if (useInheritedDynamicObject) {
                // GENERATE super.getAsDynamicObject()
                visitor.visitVarInsn(Opcodes.ALOAD, 0);
                visitor.visitMethodInsn(
                    Opcodes.INVOKESPECIAL,
                    Type.getType(type).getInternalName(),
                    "getAsDynamicObject",
                    Type.getMethodDescriptor(dynamicObjectType, new Type[0]));
              } else {
                // GENERATE null
                visitor.visitInsn(Opcodes.ACONST_NULL);
              }

              visitor.visitMethodInsn(
                  Opcodes.INVOKESPECIAL,
                  helperType.getInternalName(),
                  "<init>",
                  helperTypeConstructorDesc);
              // END

              visitor.visitFieldInsn(
                  Opcodes.PUTFIELD,
                  generatedType.getInternalName(),
                  "dynamicObjectHelper",
                  fieldSignature);
              // END
            }
          };

      // END

      // GENERATE public Convention getConvention() { return dynamicObjectHelper.getConvention(); }

      addGetter(
          HasConvention.class.getDeclaredMethod("getConvention"),
          new MethodCodeBody() {
            public void add(MethodVisitor visitor) throws Exception {

              // GENERATE dynamicObjectHelper.getConvention()

              visitor.visitVarInsn(Opcodes.ALOAD, 0);
              visitor.visitFieldInsn(
                  Opcodes.GETFIELD,
                  generatedType.getInternalName(),
                  "dynamicObjectHelper",
                  fieldSignature);
              String getterDescriptor =
                  Type.getMethodDescriptor(
                      ExtensibleDynamicObject.class.getDeclaredMethod("getConvention"));
              visitor.visitMethodInsn(
                  Opcodes.INVOKEVIRTUAL,
                  helperType.getInternalName(),
                  "getConvention",
                  getterDescriptor);
            }
          });

      // END

      // GENERATE public ExtensionContainer getExtensions() { return getConvention(); }

      addGetter(
          ExtensionAware.class.getDeclaredMethod("getExtensions"),
          new MethodCodeBody() {
            public void add(MethodVisitor visitor) throws Exception {

              // GENERATE getConvention()

              visitor.visitVarInsn(Opcodes.ALOAD, 0);
              String getterDescriptor =
                  Type.getMethodDescriptor(
                      ExtensibleDynamicObject.class.getDeclaredMethod("getConvention"));
              visitor.visitMethodInsn(
                  Opcodes.INVOKEVIRTUAL,
                  generatedType.getInternalName(),
                  "getConvention",
                  getterDescriptor);
            }
          });

      // END

      // GENERATE public DynamicObject.getAsDynamicObject() { return dynamicObjectHelper; }

      addGetter(
          DynamicObjectAware.class.getDeclaredMethod("getAsDynamicObject"),
          new MethodCodeBody() {
            public void add(MethodVisitor visitor) {

              // GENERATE dynamicObjectHelper

              visitor.visitVarInsn(Opcodes.ALOAD, 0);
              visitor.visitFieldInsn(
                  Opcodes.GETFIELD,
                  generatedType.getInternalName(),
                  "dynamicObjectHelper",
                  fieldSignature);
            }
          });

      // END
    }