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