private void writeSetter(ClassVisitor visitor, Type generatedType, ModelProperty<?> property) {
    WeaklyTypeReferencingMethod<?, Void> weakSetter = property.getSetter();
    // There is no setter for this property
    if (weakSetter == null) {
      return;
    }

    String propertyName = property.getName();
    Class<?> propertyClass = property.getType().getConcreteClass();
    Type propertyType = Type.getType(propertyClass);
    Label calledOutsideOfConstructor = new Label();

    Method setter = weakSetter.getMethod();

    // the regular typed setter
    String methodDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, propertyType);
    MethodVisitor methodVisitor =
        declareMethod(
            visitor, setter.getName(), methodDescriptor, AsmClassGeneratorUtils.signature(setter));

    putCanCallSettersFieldValueOnStack(methodVisitor, generatedType);
    jumpToLabelIfStackEvaluatesToTrue(methodVisitor, calledOutsideOfConstructor);
    throwExceptionBecauseCalledOnItself(methodVisitor);

    methodVisitor.visitLabel(calledOutsideOfConstructor);
    putStateFieldValueOnStack(methodVisitor, generatedType);
    putConstantOnStack(methodVisitor, propertyName);
    putFirstMethodArgumentOnStack(methodVisitor, propertyType);
    if (propertyClass.isPrimitive()) {
      boxType(methodVisitor, propertyClass);
    }
    invokeStateSetMethod(methodVisitor);

    finishVisitingMethod(methodVisitor);
  }
  protected static Object instantiate(Class<?> type) {
    Object returnValue;

    try {
      returnValue = type.newInstance();
    } catch (Throwable throwable) {
      throw new RuntimeException(
          "Failed to instantiate a new instance of: \'" + type.getName() + "\'", throwable);
    }

    return returnValue;
  }
 @Override
 public <E, L> EventExecutor<E, L> create(EventBus<E, L> eventBus, Method method) {
   RegisteredListener.validate(
       Objects.requireNonNull(eventBus, "Null eventBus"),
       Objects.requireNonNull(method, "Null method"));
   Class<? extends EventExecutor> executorClass =
       cache.computeIfAbsent(method, this::generateExecutor);
   try {
     return executorClass.newInstance();
   } catch (InstantiationException | IllegalAccessException e) {
     throw new RuntimeException("Unable to initialize " + executorClass, e);
   }
 }
  // the overload of type Object for Groovy coercions:  public void setFoo(Object foo)
  private void createTypeConvertingSetter(
      ClassVisitor visitor, Type generatedType, ModelProperty<?> property) {
    if (!property.isWritable() || !(property.getSchema() instanceof ScalarValueSchema)) {
      return;
    }

    Class<?> propertyClass = property.getType().getConcreteClass();
    Type propertyType = Type.getType(propertyClass);
    Class<?> boxedClass =
        propertyClass.isPrimitive() ? BOXED_TYPES.get(propertyClass) : propertyClass;
    Type boxedType = Type.getType(boxedClass);

    Method setter = property.getSetter().getMethod();
    MethodVisitor methodVisitor =
        declareMethod(
            visitor,
            setter.getName(),
            SET_OBJECT_PROPERTY_DESCRIPTOR,
            SET_OBJECT_PROPERTY_DESCRIPTOR);

    putThisOnStack(methodVisitor);
    putTypeConverterFieldValueOnStack(methodVisitor, generatedType);

    // Object converted = $typeConverter.convert(foo, Float.class, false);
    methodVisitor.visitVarInsn(ALOAD, 1); // put var #1 ('foo') on the stack
    methodVisitor.visitLdcInsn(boxedType); // push the constant Class onto the stack
    methodVisitor.visitInsn(
        propertyClass.isPrimitive()
            ? ICONST_1
            : ICONST_0); // push int 1 or 0 (interpreted as true or false) onto the stack
    methodVisitor.visitMethodInsn(
        INVOKEINTERFACE,
        TYPE_CONVERTER_TYPE.getInternalName(),
        "convert",
        COERCE_TO_SCALAR_DESCRIPTOR,
        true);
    methodVisitor.visitTypeInsn(CHECKCAST, boxedType.getInternalName());

    if (propertyClass.isPrimitive()) {
      unboxType(methodVisitor, propertyClass);
    }

    // invoke the typed setter, popping 'this' and 'converted' from the stack
    methodVisitor.visitMethodInsn(
        INVOKEVIRTUAL,
        generatedType.getInternalName(),
        setter.getName(),
        Type.getMethodDescriptor(Type.VOID_TYPE, propertyType),
        false);
    finishVisitingMethod(methodVisitor);
  }
 private void castFirstStackElement(MethodVisitor methodVisitor, Class<?> returnType) {
   if (returnType.isPrimitive()) {
     unboxType(methodVisitor, returnType);
   } else {
     methodVisitor.visitTypeInsn(CHECKCAST, Type.getInternalName(returnType));
   }
 }
  protected void injectGetByIndex(
      ClassWriter classWriter, String targetClassName, List<Field> fields) {
    MethodVisitor methodVisitor =
        classWriter.visitMethod(
            ACC_PUBLIC,
            "get",
            "(Ljava/lang/Object;I)Ljava/lang/Object;",
            null,
            new String[] {getInternalName(ILLEGAL_ACCESS_EXCEPTION.getCanonicalName())});

    Boxer boxer = new Boxer(methodVisitor);

    methodVisitor.visitCode();
    methodVisitor.visitVarInsn(ILOAD, 2);

    int maxStack = 6;

    Label[] labels = new Label[fields.size()];
    Label errorLabel = new Label();

    for (int i = 0; i < fields.size(); i++) {
      labels[i] = new Label();
    }

    methodVisitor.visitTableSwitchInsn(0, labels.length - 1, errorLabel, labels);

    if (!fields.isEmpty()) {
      maxStack--;

      for (int i = 0; i < fields.size(); i++) {
        Field field = fields.get(i);
        Class<?> type = field.getType();
        String fieldDescriptor = Type.getDescriptor(type);

        methodVisitor.visitLabel(labels[i]);

        if (i == 0) methodVisitor.visitFrame(F_APPEND, 1, new Object[] {targetClassName}, 0, null);
        else methodVisitor.visitFrame(F_SAME, 0, null, 0, null);

        if (isPublic(field)) {
          methodVisitor.visitVarInsn(ALOAD, 1);
          methodVisitor.visitTypeInsn(CHECKCAST, targetClassName);
          methodVisitor.visitFieldInsn(GETFIELD, targetClassName, field.getName(), fieldDescriptor);

          boxer.box(Type.getType(type));
        } else {
          injectReflectiveGetter(methodVisitor);
        }

        methodVisitor.visitInsn(ARETURN);
      }

      methodVisitor.visitLabel(errorLabel);
      methodVisitor.visitFrame(F_SAME, 0, null, 0, null);
    }

    injectException(methodVisitor, IllegalAccessException.class);
    methodVisitor.visitMaxs(maxStack, 3);
    methodVisitor.visitEnd();
  }
 private Class<?> makeClassWithoutAPackage() {
   // Use ASM since we can't use mockito on Class to make it return a package-less class, Class is
   // a final class.
   ClassWriter writer = new ClassWriter(0);
   writer.visit(V1_5, ACC_PUBLIC, "ClazzWithNoPackage", null, "java/lang/Object", null);
   writer.visitEnd();
   byte[] bytes = writer.toByteArray();
   class ClazzLoader extends ClassLoader {
     Class<?> defineClass(byte[] bytes) {
       return defineClass(null, bytes, 0, bytes.length);
     }
   };
   Class<?> clazz = new ClazzLoader().defineClass(bytes);
   assertEquals("ClazzWithNoPackage", clazz.getName());
   return clazz;
 }
 private Method getToStringMethod(Class<?> managedTypeClass) {
   try {
     return managedTypeClass.getMethod("toString");
   } catch (NoSuchMethodException e) {
     return null;
   }
 }
  private void writeDelegateMethods(
      final ClassVisitor visitor,
      final Type generatedType,
      StructSchema<?> delegateSchema,
      Set<Class<?>> typesToDelegate) {
    Class<?> delegateClass = delegateSchema.getType().getConcreteClass();
    Type delegateType = Type.getType(delegateClass);
    Map<Equivalence.Wrapper<Method>, Map<Class<?>, Method>> methodsToDelegate = Maps.newHashMap();
    for (Class<?> typeToDelegate : typesToDelegate) {
      for (Method methodToDelegate : typeToDelegate.getMethods()) {
        if (ModelSchemaUtils.isIgnoredMethod(methodToDelegate)) {
          continue;
        }
        Equivalence.Wrapper<Method> methodKey = METHOD_EQUIVALENCE.wrap(methodToDelegate);
        Map<Class<?>, Method> methodsByReturnType = methodsToDelegate.get(methodKey);
        if (methodsByReturnType == null) {
          methodsByReturnType = Maps.newHashMap();
          methodsToDelegate.put(methodKey, methodsByReturnType);
        }
        methodsByReturnType.put(methodToDelegate.getReturnType(), methodToDelegate);
      }
    }
    Set<Equivalence.Wrapper<Method>> delegateMethodKeys =
        ImmutableSet.copyOf(
            Iterables.transform(
                Arrays.asList(delegateClass.getMethods()),
                new Function<Method, Equivalence.Wrapper<Method>>() {
                  @Override
                  public Equivalence.Wrapper<Method> apply(Method method) {
                    return METHOD_EQUIVALENCE.wrap(method);
                  }
                }));
    for (Map.Entry<Equivalence.Wrapper<Method>, Map<Class<?>, Method>> entry :
        methodsToDelegate.entrySet()) {
      Equivalence.Wrapper<Method> methodKey = entry.getKey();
      if (!delegateMethodKeys.contains(methodKey)) {
        continue;
      }

      Map<Class<?>, Method> methodsByReturnType = entry.getValue();
      for (Method methodToDelegate : methodsByReturnType.values()) {
        writeDelegatedMethod(visitor, generatedType, delegateType, methodToDelegate);
      }
    }
  }
 static {
   ASMEventExecutorFactory instance = null;
   try {
     Class.forName("org.objectweb.asm.Opcodes");
     instance = new ASMEventExecutorFactory();
   } catch (ClassNotFoundException ignored) {
   }
   INSTANCE = instance;
 }
  @Override
  public FieldAccessor build(ClassLoader classLoader) {
    String targetClassType = getInternalName(this.getTarget().getName());

    ClassWriter classWriter = this.getClassWriter();

    injectFieldTable(classWriter);
    injectConstructor(classWriter);
    injectGetTargetClass(classWriter, this.getTarget());

    List<Field> fields = new ArrayList<>();
    Class<?> current = this.getTarget();
    while (current != Object.class) {
      for (Field field : current.getDeclaredFields()) {
        fields.add(field);
      }
      current = current.getSuperclass();
    }

    injectGetByIndex(classWriter, targetClassType, fields);
    injectSetByIndex(classWriter, targetClassType, fields);

    injectGetByName(classWriter);
    injectSetByName(classWriter);

    injectGetFieldTable(classWriter);
    injectGetIndex(classWriter);

    classWriter.visitEnd();

    Class<?> result =
        CompilerService.create(classLoader)
            .defineClass(
                getExternalName(
                    getAccessorNameInternal(
                        this.getTarget(),
                        this
                            .getAccessorType())), // this is somewhat redundant but maybe in the
                                                  // future the class-name-format changes
                this.getClassWriter().toByteArray());

    return (FieldAccessor) instantiate(result);
  }
 protected void injectException(
     MethodVisitor methodVisitor, Class<? extends Throwable> throwable) {
   methodVisitor.visitTypeInsn(NEW, getInternalName(throwable.getCanonicalName()));
   methodVisitor.visitInsn(DUP);
   methodVisitor.visitTypeInsn(NEW, "java/lang/StringBuilder");
   methodVisitor.visitInsn(DUP);
   methodVisitor.visitLdcInsn("Invalid index: ");
   methodVisitor.visitMethodInsn(
       INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V");
   methodVisitor.visitVarInsn(ILOAD, 2);
   methodVisitor.visitMethodInsn(
       INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;");
   methodVisitor.visitMethodInsn(
       INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
   methodVisitor.visitMethodInsn(
       INVOKESPECIAL,
       getInternalName(throwable.getCanonicalName()),
       "<init>",
       "(Ljava/lang/String;)V");
   methodVisitor.visitInsn(ATHROW);
 }
 private static void resetLambdaClassSequenceNumber() {
   try {
     Field counterField =
         Class.forName("java.lang.invoke.InnerClassLambdaMetafactory").getDeclaredField("counter");
     counterField.setAccessible(true);
     AtomicInteger counter = (AtomicInteger) counterField.get(null);
     counter.set(0);
   } catch (Throwable t) {
     // print to stdout to keep in sync with other log output
     System.out.println(
         "WARNING: Failed to start class numbering from one. Don't worry, it's cosmetic, "
             + "but please file a bug report and tell on which JDK version this happened.");
     t.printStackTrace(System.out);
   }
 }
 private void unboxType(MethodVisitor methodVisitor, Class<?> primitiveClass) {
   // Float f = (Float) tmp
   // f==null?0:f.floatValue()
   Class<?> boxedType = BOXED_TYPES.get(primitiveClass);
   Type primitiveType = Type.getType(primitiveClass);
   methodVisitor.visitTypeInsn(CHECKCAST, Type.getInternalName(boxedType));
   methodVisitor.visitInsn(DUP);
   Label exit = new Label();
   Label elseValue = new Label();
   methodVisitor.visitJumpInsn(IFNONNULL, elseValue);
   methodVisitor.visitInsn(POP);
   pushDefaultValue(methodVisitor, primitiveClass);
   methodVisitor.visitJumpInsn(GOTO, exit);
   methodVisitor.visitLabel(elseValue);
   methodVisitor.visitMethodInsn(
       INVOKEVIRTUAL,
       Type.getInternalName(boxedType),
       primitiveClass.getSimpleName() + "Value",
       Type.getMethodDescriptor(primitiveType),
       false);
   methodVisitor.visitLabel(exit);
 }
示例#15
0
  public static FieldAccess get(Class type) {
    ArrayList<Field> fields = new ArrayList<Field>();
    Class nextClass = type;
    while (nextClass != Object.class) {
      Field[] declaredFields = nextClass.getDeclaredFields();
      fields.addAll(Arrays.asList(declaredFields));
      nextClass = nextClass.getSuperclass();
    }

    String[] fieldNames = new String[fields.size()];
    Class[] fieldTypes = new Class[fields.size()];
    for (int i = 0, n = fieldNames.length; i < n; i++) {
      fieldNames[i] = fields.get(i).getName();
      fieldTypes[i] = fields.get(i).getType();
    }

    String className = type.getName();
    String accessClassName = className + "FieldAccess";
    if (accessClassName.startsWith("java.")) accessClassName = "reflectasm." + accessClassName;
    Class accessClass = null;

    AccessClassLoader loader = AccessClassLoader.get(type);
    synchronized (loader) {
      try {
        accessClass = loader.loadClass(accessClassName);
      } catch (ClassNotFoundException ignored) {
        String accessClassNameInternal = accessClassName.replace('.', '/');
        String classNameInternal = className.replace('.', '/');

        ClassWriter cw = new ClassWriter(0);
        cw.visit(
            V1_1,
            ACC_PUBLIC + ACC_SUPER,
            accessClassNameInternal,
            null,
            "com/esotericsoftware/reflectasm/FieldAccess",
            null);
        insertConstructor(cw);
        insertGetObject(cw, classNameInternal, fields);
        insertSetObject(cw, classNameInternal, fields);
        insertGetPrimitive(cw, classNameInternal, fields, Type.BOOLEAN_TYPE);
        insertSetPrimitive(cw, classNameInternal, fields, Type.BOOLEAN_TYPE);
        insertGetPrimitive(cw, classNameInternal, fields, Type.BYTE_TYPE);
        insertSetPrimitive(cw, classNameInternal, fields, Type.BYTE_TYPE);
        insertGetPrimitive(cw, classNameInternal, fields, Type.SHORT_TYPE);
        insertSetPrimitive(cw, classNameInternal, fields, Type.SHORT_TYPE);
        insertGetPrimitive(cw, classNameInternal, fields, Type.INT_TYPE);
        insertSetPrimitive(cw, classNameInternal, fields, Type.INT_TYPE);
        insertGetPrimitive(cw, classNameInternal, fields, Type.LONG_TYPE);
        insertSetPrimitive(cw, classNameInternal, fields, Type.LONG_TYPE);
        insertGetPrimitive(cw, classNameInternal, fields, Type.DOUBLE_TYPE);
        insertSetPrimitive(cw, classNameInternal, fields, Type.DOUBLE_TYPE);
        insertGetPrimitive(cw, classNameInternal, fields, Type.FLOAT_TYPE);
        insertSetPrimitive(cw, classNameInternal, fields, Type.FLOAT_TYPE);
        insertGetPrimitive(cw, classNameInternal, fields, Type.CHAR_TYPE);
        insertSetPrimitive(cw, classNameInternal, fields, Type.CHAR_TYPE);
        insertGetString(cw, classNameInternal, fields);
        cw.visitEnd();
        accessClass = loader.defineClass(accessClassName, cw.toByteArray());
      }
    }
    try {
      FieldAccess access = (FieldAccess) accessClass.newInstance();
      access.fieldNames = fieldNames;
      access.fieldTypes = fieldTypes;
      return access;
    } catch (Throwable t) {
      throw new RuntimeException("Error constructing field access class: " + accessClassName, t);
    }
  }
示例#16
0
 protected static String toSafeName(Class<?> clazz) {
   return clazz.getCanonicalName().replace("[]", "Array").replace(".", "_");
 }
  /**
   * 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);
  }
 private void putClassOnStack(MethodVisitor methodVisitor, Class<?> managedTypeClass) {
   putConstantOnStack(methodVisitor, managedTypeClass.getName());
   methodVisitor.visitMethodInsn(
       INVOKESTATIC, CLASS_INTERNAL_NAME, "forName", FOR_NAME_METHOD_DESCRIPTOR, false);
 }
  @SuppressWarnings({"rawtypes", "unchecked"})
  public static <T> ConstructorAccess<T> get(Class<T> type) {
    try {
      type.getConstructor((Class[]) null);
    } catch (Exception ex) {
      if (type.isMemberClass() && !Modifier.isStatic(type.getModifiers()))
        throw new RuntimeException(
            "Class cannot be created (non-static member class): " + type.getName());
      else
        throw new RuntimeException(
            "Class cannot be created (missing no-arg constructor): " + type.getName());
    }

    AccessClassLoader loader = AccessClassLoader.get(type);

    String className = type.getName();
    String accessClassName = className + "ConstructorAccess";
    if (accessClassName.startsWith("java.")) accessClassName = "reflectasm." + accessClassName;
    Class accessClass = null;
    try {
      accessClass = loader.loadClass(accessClassName);
    } catch (ClassNotFoundException ignored) {
    }
    if (accessClass == null) {
      String accessClassNameInternal = accessClassName.replace('.', '/');
      String classNameInternal = className.replace('.', '/');

      ClassWriter cw = new ClassWriter(0);
      cw.visit(
          V1_1,
          ACC_PUBLIC + ACC_SUPER,
          accessClassNameInternal,
          null,
          "com/esotericsoftware/reflectasm/ConstructorAccess",
          null);
      MethodVisitor mv;
      {
        mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(
            INVOKESPECIAL, "com/esotericsoftware/reflectasm/ConstructorAccess", "<init>", "()V");
        mv.visitInsn(RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
      }
      {
        mv = cw.visitMethod(ACC_PUBLIC, "newInstance", "()Ljava/lang/Object;", null, null);
        mv.visitCode();
        mv.visitTypeInsn(NEW, classNameInternal);
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL, classNameInternal, "<init>", "()V");
        mv.visitInsn(ARETURN);
        mv.visitMaxs(2, 1);
        mv.visitEnd();
      }
      cw.visitEnd();
      byte[] data = cw.toByteArray();
      accessClass = loader.defineClass(accessClassName, data);
    }
    try {
      return (ConstructorAccess) accessClass.newInstance();
    } catch (Exception ex) {
      throw new RuntimeException(
          "Error constructing constructor access class: " + accessClassName, ex);
    }
  }