@Override
 public AnnotationAppender onParameterizedType(TypeDescription.Generic parameterizedType) {
   StringBuilder typePath = new StringBuilder(this.typePath);
   for (int index = 0; index < parameterizedType.asErasure().getSegmentCount(); index++) {
     typePath = typePath.append(INNER_CLASS_PATH);
   }
   AnnotationAppender annotationAppender = apply(parameterizedType, typePath.toString());
   TypeDescription.Generic ownerType = parameterizedType.getOwnerType();
   if (ownerType != null) {
     annotationAppender =
         ownerType.accept(
             new ForTypeAnnotations(
                 annotationAppender, annotationValueFilter, typeReference, this.typePath));
   }
   int index = 0;
   for (TypeDescription.Generic typeArgument : parameterizedType.getTypeArguments()) {
     annotationAppender =
         typeArgument.accept(
             new ForTypeAnnotations(
                 annotationAppender,
                 annotationValueFilter,
                 typeReference,
                 typePath.toString() + index++ + INDEXED_TYPE_DELIMITER));
   }
   return annotationAppender;
 }
 private void visitNested(java.lang.reflect.Type type, StringBuilder builder) {
   if (type instanceof Class) {
     Class<?> cl = (Class<?>) type;
     if (cl.isPrimitive()) {
       builder.append(Type.getType(cl).getDescriptor());
     } else {
       builder.append('L');
       builder.append(cl.getName().replace('.', '/'));
     }
   } else {
     visitType(type, builder);
   }
 }
 @Override
 public AnnotationAppender onNonGenericType(TypeDescription.Generic typeDescription) {
   StringBuilder typePath = new StringBuilder(this.typePath);
   for (int index = 0; index < typeDescription.asErasure().getSegmentCount(); index++) {
     typePath = typePath.append(INNER_CLASS_PATH);
   }
   AnnotationAppender annotationAppender = apply(typeDescription, typePath.toString());
   if (typeDescription.isArray()) {
     annotationAppender =
         typeDescription
             .getComponentType()
             .accept(
                 new ForTypeAnnotations(
                     annotationAppender,
                     annotationValueFilter,
                     typeReference,
                     this.typePath + COMPONENT_TYPE_PATH)); // Impossible to be inner class
   }
   return annotationAppender;
 }
 /** Generates the signature for the given constructor */
 private String signature(Constructor<?> constructor) {
   StringBuilder builder = new StringBuilder();
   if (constructor.getTypeParameters().length > 0) {
     builder.append('<');
     for (TypeVariable<?> typeVariable : constructor.getTypeParameters()) {
       builder.append(typeVariable.getName());
       for (java.lang.reflect.Type bound : typeVariable.getBounds()) {
         builder.append(':');
         visitType(bound, builder);
       }
     }
     builder.append('>');
   }
   builder.append('(');
   for (java.lang.reflect.Type paramType : constructor.getGenericParameterTypes()) {
     visitType(paramType, builder);
   }
   builder.append(")V");
   for (java.lang.reflect.Type exceptionType : constructor.getGenericExceptionTypes()) {
     builder.append('^');
     visitType(exceptionType, builder);
   }
   return builder.toString();
 }
 private MethodVisitor createConstructor(
     final int access,
     final String name,
     final String desc,
     final String signature,
     final String[] exceptions) {
   Type[] args = Type.getArgumentTypes(desc);
   StringBuilder newDesc = new StringBuilder("(");
   for (Type arg : args) {
     newDesc.append(arg.getDescriptor());
   }
   newDesc.append("Ljava/util/Map;"); // the closure map
   if (generateDelegateField) {
     newDesc.append(BytecodeHelper.getTypeDescription(delegateClass));
   }
   newDesc.append(")V");
   MethodVisitor mv = super.visitMethod(access, name, newDesc.toString(), signature, exceptions);
   mv.visitCode();
   initializeDelegateClosure(mv, args.length);
   if (generateDelegateField) {
     initializeDelegateObject(mv, args.length + 1);
   }
   mv.visitVarInsn(ALOAD, 0);
   int idx = 1;
   for (Type arg : args) {
     if (isPrimitive(arg)) {
       mv.visitIntInsn(getLoadInsn(arg), idx);
     } else {
       mv.visitVarInsn(ALOAD, idx); // load argument i
     }
     idx += registerLen(arg);
   }
   mv.visitMethodInsn(
       INVOKESPECIAL, BytecodeHelper.getClassInternalName(superClass), "<init>", desc);
   mv.visitInsn(RETURN);
   int max = idx + 1 + (generateDelegateField ? 1 : 0);
   mv.visitMaxs(max, max);
   mv.visitEnd();
   return EMPTY_VISITOR;
 }
 private void visitType(java.lang.reflect.Type type, StringBuilder builder) {
   if (type instanceof Class) {
     Class<?> cl = (Class<?>) type;
     if (cl.isPrimitive()) {
       builder.append(Type.getType(cl).getDescriptor());
     } else {
       if (cl.isArray()) {
         builder.append(cl.getName().replace('.', '/'));
       } else {
         builder.append('L');
         builder.append(cl.getName().replace('.', '/'));
         builder.append(';');
       }
     }
   } else if (type instanceof ParameterizedType) {
     ParameterizedType parameterizedType = (ParameterizedType) type;
     visitNested(parameterizedType.getRawType(), builder);
     builder.append('<');
     for (java.lang.reflect.Type param : parameterizedType.getActualTypeArguments()) {
       visitType(param, builder);
     }
     builder.append(">;");
   } else if (type instanceof WildcardType) {
     WildcardType wildcardType = (WildcardType) type;
     if (wildcardType.getUpperBounds().length == 1
         && wildcardType.getUpperBounds()[0].equals(Object.class)) {
       if (wildcardType.getLowerBounds().length == 0) {
         builder.append('*');
         return;
       }
     } else {
       for (java.lang.reflect.Type upperType : wildcardType.getUpperBounds()) {
         builder.append('+');
         visitType(upperType, builder);
       }
     }
     for (java.lang.reflect.Type lowerType : wildcardType.getLowerBounds()) {
       builder.append('-');
       visitType(lowerType, builder);
     }
   } else if (type instanceof TypeVariable) {
     TypeVariable<?> typeVar = (TypeVariable) type;
     builder.append('T');
     builder.append(typeVar.getName());
     builder.append(';');
   } else if (type instanceof GenericArrayType) {
     GenericArrayType arrayType = (GenericArrayType) type;
     builder.append('[');
     visitType(arrayType.getGenericComponentType(), builder);
   } else {
     throw new IllegalArgumentException(
         String.format("Cannot generate signature for %s.", type));
   }
 }
  /**
   * Generates an implementation of the given managed type.
   *
   * <p>The generated class will implement/extend the managed type and will:
   *
   * <ul>
   *   <li>provide implementations for abstract getters and setters that delegate to model nodes
   *   <li>provide a `toString()` implementation
   *   <li>mix-in implementation of {@link ManagedInstance}
   *   <li>provide a constructor that accepts a {@link ModelElementState}, which will be used to
   *       implement the above.
   * </ul>
   *
   * In case a delegate schema is supplied, the generated class will also have:
   *
   * <ul>
   *   <li>a constructor that also takes a delegate instance
   *   <li>methods that call through to the delegate instance
   * </ul>
   */
  public <T, M extends T, D extends T> Class<? extends M> generate(
      StructSchema<M> viewSchema, @Nullable StructSchema<D> delegateSchema) {
    if (delegateSchema != null
        && Modifier.isAbstract(delegateSchema.getType().getConcreteClass().getModifiers())) {
      throw new IllegalArgumentException("Delegate type must be null or a non-abstract type");
    }
    ClassWriter visitor = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);

    ModelType<M> viewType = viewSchema.getType();

    StringBuilder generatedTypeNameBuilder = new StringBuilder(viewType.getName());
    if (delegateSchema != null) {
      generatedTypeNameBuilder
          .append("$BackedBy_")
          .append(delegateSchema.getType().getName().replaceAll("\\.", "_"));
    } else {
      generatedTypeNameBuilder.append("$Impl");
    }

    String generatedTypeName = generatedTypeNameBuilder.toString();
    Type generatedType = Type.getType("L" + generatedTypeName.replaceAll("\\.", "/") + ";");

    Class<M> viewClass = viewType.getConcreteClass();
    Class<?> superclass;
    final ImmutableSet.Builder<String> interfacesToImplement = ImmutableSet.builder();
    final ImmutableSet.Builder<Class<?>> typesToDelegate = ImmutableSet.builder();
    typesToDelegate.add(viewClass);
    interfacesToImplement.add(MANAGED_INSTANCE_TYPE);
    if (viewClass.isInterface()) {
      superclass = Object.class;
      interfacesToImplement.add(Type.getInternalName(viewClass));
    } else {
      superclass = viewClass;
    }
    // TODO:LPTR This should be removed once BinaryContainer is a ModelMap
    // We need to also implement all the interfaces of the delegate type because otherwise
    // BinaryContainer won't recognize managed binaries as BinarySpecInternal
    if (delegateSchema != null) {
      ModelSchemaUtils.walkTypeHierarchy(
          delegateSchema.getType().getConcreteClass(),
          new ModelSchemaUtils.TypeVisitor<D>() {
            @Override
            public void visitType(Class<? super D> type) {
              if (type.isInterface()) {
                typesToDelegate.add(type);
                interfacesToImplement.add(Type.getInternalName(type));
              }
            }
          });
    }

    generateProxyClass(
        visitor,
        viewSchema,
        delegateSchema,
        interfacesToImplement.build(),
        typesToDelegate.build(),
        generatedType,
        Type.getType(superclass));

    ClassLoader targetClassLoader = viewClass.getClassLoader();
    if (delegateSchema != null) {
      // TODO - remove this once the above is removed
      try {
        viewClass.getClassLoader().loadClass(delegateSchema.getType().getConcreteClass().getName());
      } catch (ClassNotFoundException e) {
        // Delegate class is not visible to managed view type -> view type is more general than
        // delegate type, so use the delegate classloader instead
        targetClassLoader = delegateSchema.getType().getConcreteClass().getClassLoader();
      }
    }

    return defineClass(visitor, targetClassLoader, generatedTypeName);
  }