예제 #1
0
    public Class<? extends T> generate() {
      visitor.visitEnd();

      byte[] bytecode = visitor.toByteArray();
      return DEFINE_CLASS_METHOD.invoke(
          type.getClassLoader(), typeName, bytecode, 0, bytecode.length);
    }
  /**
   * 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);
  }
예제 #3
0
 private InnerLoader findClassLoader(Class clazz) {
   ClassLoader cl = clazz.getClassLoader();
   if (cl == null) cl = this.getClass().getClassLoader();
   return new InnerLoader(cl);
 }
  public static List<InstantiatorDefinition> extractDefinitions(final Type target)
      throws IOException {
    final List<InstantiatorDefinition> constructors = new ArrayList<InstantiatorDefinition>();

    final Class<?> targetClass = TypeHelper.toClass(target);

    ClassLoader cl = targetClass.getClassLoader();
    if (cl == null) {
      cl = ClassLoader.getSystemClassLoader();
    }

    final String fileName = targetClass.getName().replace('.', '/') + ".class";
    final InputStream is = cl.getResourceAsStream(fileName);
    try {
      if (is == null) {
        throw new IOException("Cannot find file " + fileName + " in " + cl);
      }
      ClassReader classReader = new ClassReader(is);
      classReader.accept(
          new ClassVisitor(Opcodes.ASM5) {
            List<String> genericTypeNames;

            @Override
            public void visit(
                int version,
                int access,
                String name,
                String signature,
                String superName,
                String[] interfaces) {
              if (signature != null) {
                genericTypeNames = AsmUtils.extractGenericTypeNames(signature);
              } else {
                genericTypeNames = Collections.emptyList();
              }
              super.visit(version, access, name, signature, superName, interfaces);
            }

            @Override
            public MethodVisitor visitMethod(
                int access,
                final String methodName,
                String desc,
                String signature,
                String[] exceptions) {
              final boolean isConstructor = "<init>".equals(methodName);
              if ((Opcodes.ACC_PUBLIC & access) == Opcodes.ACC_PUBLIC
                  && (isConstructor
                      || ((Opcodes.ACC_STATIC & access) == Opcodes.ACC_STATIC
                          && !desc.endsWith("V")))) {
                final List<String> descTypes = AsmUtils.extractTypeNames(desc);

                final List<String> genericTypes;
                final List<String> names = new ArrayList<String>();
                if (signature != null) {
                  genericTypes = AsmUtils.extractTypeNames(signature);
                } else {
                  genericTypes = descTypes;
                }

                if (!isConstructor) {
                  if (descTypes.size() > 0) {
                    try {
                      final Type genericType =
                          AsmUtils.toGenericType(
                              descTypes.get(descTypes.size() - 1), genericTypeNames, target);
                      if (!targetClass.isAssignableFrom(TypeHelper.toClass(genericType))) {
                        return null;
                      }
                    } catch (ClassNotFoundException e) {
                      return null;
                    }
                  } else return null;
                }

                return new MethodVisitor(Opcodes.ASM5) {

                  Label firstLabel;
                  Label lastLabel;

                  @Override
                  public void visitLabel(Label label) {
                    if (firstLabel == null) {
                      firstLabel = label;
                    }
                    lastLabel = label;
                  }

                  @Override
                  public void visitLocalVariable(
                      String name,
                      String desc,
                      String signature,
                      Label start,
                      Label end,
                      int index) {
                    if (start.equals(firstLabel) && end.equals(lastLabel) && !"this".equals(name)) {
                      names.add(name);
                    }
                  }

                  @Override
                  public void visitEnd() {
                    try {
                      final List<Parameter> parameters = new ArrayList<Parameter>();

                      int l = descTypes.size() - (isConstructor ? 0 : 1);
                      for (int i = 0; i < l; i++) {
                        String name = "arg" + i;
                        if (i < names.size()) {
                          name = names.get(i);
                        }
                        parameters.add(
                            createParameter(i, name, descTypes.get(i), genericTypes.get(i)));
                      }

                      final Member executable;

                      if (isConstructor) {
                        executable = targetClass.getDeclaredConstructor(toTypeArray(parameters));
                      } else {
                        executable =
                            targetClass.getDeclaredMethod(methodName, toTypeArray(parameters));
                      }
                      constructors.add(
                          new ExecutableInstantiatorDefinition(
                              executable, parameters.toArray(new Parameter[0])));
                    } catch (Exception e) {
                      ErrorHelper.rethrow(e);
                    }
                  }

                  private Class<?>[] toTypeArray(List<Parameter> parameters) {
                    Class<?>[] types = new Class<?>[parameters.size()];
                    for (int i = 0; i < types.length; i++) {
                      types[i] = parameters.get(i).getType();
                    }
                    return types;
                  }

                  private Parameter createParameter(
                      int index, String name, String desc, String signature) {
                    try {

                      Type basicType = AsmUtils.toGenericType(desc, genericTypeNames, target);
                      Type genericType = basicType;
                      if (signature != null) {
                        Type type = AsmUtils.toGenericType(signature, genericTypeNames, target);
                        if (type != null) {
                          genericType = type;
                        }
                      }
                      return new Parameter(index, name, TypeHelper.toClass(basicType), genericType);
                    } catch (ClassNotFoundException e) {
                      throw new Error("Unexpected error " + e, e);
                    }
                  }
                };
              } else {
                return null;
              }
            }
          },
          0);
    } finally {
      try {
        is.close();
      } catch (Exception e) {
      }
    }

    return constructors;
  }