@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);
  }
Example #2
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);
    }
  }