Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /******************************************************************************
- * Inspired by https://github.com/EsotericSoftware/reflectasm
- * the main idea is to take away introspection from ReflectASM
- *
- * You must obtain reflection member (Constructor,Method or Field)
- * yourself then pass it to FastReflection.of() method to obtain
- * code generated access-object...
- *
- * Also (since it operate per-member basis) it takes away ugly switches
- * into generated bytecode, supports parametrized constructors and
- * static fields/members...
- */
- package com.esotericsoftware.reflectasm.dimzon;
- import org.objectweb.asm.ClassWriter;
- import org.objectweb.asm.MethodVisitor;
- import org.objectweb.asm.Type;
- import java.io.File;
- import java.lang.reflect.Member;
- import java.lang.reflect.Modifier;
- import java.nio.charset.StandardCharsets;
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- import java.util.ArrayList;
- import java.util.Objects;
- import static org.objectweb.asm.Opcodes.*;
- @SuppressWarnings("UnusedDeclaration")
- public final class FastReflection {
- public static void main(String[] args) throws Throwable {
- Class ps = System.out.getClass();
- java.lang.reflect.Method psMethod = ps.getMethod("println", Object.class);
- Method println = of(psMethod);
- println.invoke(System.out, "System.out");
- println.invoke(System.err, "System.err");
- java.lang.reflect.Method nanoTime = System.class.getMethod("nanoTime");
- println.invoke(System.out, of(nanoTime).invokeStatic());
- println.invoke(System.err, of(nanoTime).invokeStatic());
- java.lang.reflect.Constructor<File> fileConstructor = File.class.getConstructor(String.class);
- Object o = of(fileConstructor).newInstance("c:\\bla.txt");
- System.out.println(o);
- java.lang.reflect.Field field = System.class.getField("out");
- Object o1 = of(field).get(null);
- System.out.println(o1);
- }
- private static final Object[] EMPTY_VARARGS = new Object[0];
- private static final ThreadLocal<MessageDigest> md5 = new ThreadLocal<MessageDigest>() {
- @Override
- protected MessageDigest initialValue() {
- try {
- return MessageDigest.getInstance("MD5");
- } catch (NoSuchAlgorithmException nsae) {
- throw new RuntimeException(nsae);
- }
- }
- };
- private static String memberAccessClassName(Member member) {
- byte[] md5Bytes = md5.get().digest(member.toString().getBytes(StandardCharsets.UTF_8));
- String sign = member.getDeclaringClass().getName()
- + "__"
- + javax.xml.bind.DatatypeConverter.printHexBinary(md5Bytes);
- if (sign.startsWith("java.")) sign = "reflectasm." + sign;
- return sign;
- }
- public static Constructor of(java.lang.reflect.Constructor ctor) {
- Objects.requireNonNull(ctor);
- Class accessClass;
- String accessClassName = memberAccessClassName(ctor);
- AccessClassLoader_2 loader = AccessClassLoader_2.get(ctor.getDeclaringClass());
- //noinspection SynchronizationOnLocalVariableOrMethodParameter
- synchronized (loader) {
- try {
- accessClass = loader.loadClass(accessClassName);
- } catch (ClassNotFoundException ignored) {
- byte[] byteCode = createAccessor(accessClassName, ctor);
- accessClass = loader.defineClass(accessClassName, byteCode);
- }
- }
- try {
- Constructor m = (Constructor) accessClass.newInstance();
- m._member = ctor;
- return m;
- } catch (Throwable e) {
- throw new RuntimeException("Error constructing constructor access class: " + accessClassName, e);
- }
- }
- public static Method of(java.lang.reflect.Method method) {
- Objects.requireNonNull(method);
- Class accessClass;
- String accessClassName = memberAccessClassName(method);
- AccessClassLoader_2 loader = AccessClassLoader_2.get(method.getDeclaringClass());
- //noinspection SynchronizationOnLocalVariableOrMethodParameter
- synchronized (loader) {
- try {
- accessClass = loader.loadClass(accessClassName);
- } catch (ClassNotFoundException ignored) {
- byte[] byteCode = createAccessor(accessClassName, method);
- accessClass = loader.defineClass(accessClassName, byteCode);
- }
- }
- try {
- Method m = (Method) accessClass.newInstance();
- m._member = method;
- return m;
- } catch (Throwable e) {
- throw new RuntimeException("Error constructing method access class: " + accessClassName, e);
- }
- }
- public static Field of(java.lang.reflect.Field field) {
- Objects.requireNonNull(field);
- Class accessClass;
- String accessClassName = memberAccessClassName(field);
- AccessClassLoader_2 loader = AccessClassLoader_2.get(field.getDeclaringClass());
- //noinspection SynchronizationOnLocalVariableOrMethodParameter
- synchronized (loader) {
- try {
- accessClass = loader.loadClass(accessClassName);
- } catch (ClassNotFoundException ignored) {
- byte[] byteCode = createAccessor(accessClassName, field);
- accessClass = loader.defineClass(accessClassName, byteCode);
- }
- }
- try {
- Field m = (Field) accessClass.newInstance();
- m._member = field;
- return m;
- } catch (Throwable e) {
- throw new RuntimeException("Error constructing field access class: " + accessClassName, e);
- }
- }
- private static byte[] createAccessor(String accessClassName, java.lang.reflect.Constructor<?> member) {
- String className = member.getDeclaringClass().getName();
- String classNameInternal = internalClassName(className);
- ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
- injectConstructor(accessClassName, Constructor.class, cw);
- {
- MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "newInstance",
- "([Ljava/lang/Object;)Ljava/lang/Object;", null, null);
- mv.visitCode();
- mv.visitTypeInsn(NEW, classNameInternal);
- mv.visitInsn(DUP);
- StringBuilder buffer = new StringBuilder(128);
- buffer.setLength(0);
- buffer.append('(');
- injectVarArgs(mv, buffer, member.getParameterTypes(), 1);
- buffer.append(")V");
- mv.visitMethodInsn(INVOKESPECIAL, classNameInternal, "<init>", buffer.toString());
- mv.visitInsn(ARETURN);
- mv.visitMaxs(0, 0);
- mv.visitEnd();
- }
- cw.visitEnd();
- return cw.toByteArray();
- }
- private static String internalClassName(String classicClassName) {
- return classicClassName.replace('.', '/');
- }
- private static byte[] createAccessor(String accessClassName, java.lang.reflect.Field member) {
- String className = member.getDeclaringClass().getName();
- String classNameInternal = internalClassName(className);
- boolean isStatic = Modifier.isStatic(member.getModifiers());
- Class<?> memberType = member.getType();
- Type fieldType = Type.getType(memberType);
- int fieldTypeSort = fieldType.getSort();
- ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
- injectConstructor(accessClassName, Field.class, cw);
- MethodVisitor mv;
- {
- mv = cw.visitMethod(ACC_PUBLIC, "get",
- "(Ljava/lang/Object;)Ljava/lang/Object;", null, null);
- mv.visitCode();
- if (!isStatic) {
- mv.visitVarInsn(ALOAD, 1);
- mv.visitTypeInsn(CHECKCAST, classNameInternal);
- }
- mv.visitFieldInsn(isStatic ? GETSTATIC : GETFIELD, classNameInternal, member.getName(), Type.getDescriptor(memberType));
- injectBoxing(mv, fieldTypeSort);
- mv.visitInsn(ARETURN);
- mv.visitMaxs(0, 0);
- mv.visitEnd();
- }
- {
- mv = cw.visitMethod(ACC_PUBLIC, "set",
- "(Ljava/lang/Object;Ljava/lang/Object;)V", null, null);
- mv.visitCode();
- if (!isStatic) {
- mv.visitVarInsn(ALOAD, 1);
- mv.visitTypeInsn(CHECKCAST, classNameInternal);
- }
- mv.visitVarInsn(ALOAD, 2);
- injectUnBoxing(mv, fieldType);
- mv.visitFieldInsn(isStatic ? PUTSTATIC : PUTFIELD, classNameInternal, member.getName(), fieldType.getDescriptor());
- mv.visitInsn(RETURN);
- mv.visitMaxs(0, 0);
- mv.visitEnd();
- }
- switch (fieldTypeSort) {
- case Type.BOOLEAN:
- injectPrimitiveGetterSetter("Boolean", IRETURN, ILOAD,
- fieldType, fieldTypeSort, cw, member, isStatic, classNameInternal);
- break;
- case Type.BYTE:
- injectPrimitiveGetterSetter("Byte", IRETURN, ILOAD,
- fieldType, fieldTypeSort, cw, member, isStatic, classNameInternal);
- break;
- case Type.CHAR:
- injectPrimitiveGetterSetter("Char", IRETURN, ILOAD,
- fieldType, fieldTypeSort, cw, member, isStatic, classNameInternal);
- break;
- case Type.SHORT:
- injectPrimitiveGetterSetter("Short", IRETURN, ILOAD,
- fieldType, fieldTypeSort, cw, member, isStatic, classNameInternal);
- break;
- case Type.INT:
- injectPrimitiveGetterSetter("Int", IRETURN, ILOAD,
- fieldType, fieldTypeSort, cw, member, isStatic, classNameInternal);
- break;
- case Type.FLOAT:
- injectPrimitiveGetterSetter("Float", FRETURN, FLOAD,
- fieldType, fieldTypeSort, cw, member, isStatic, classNameInternal);
- break;
- case Type.LONG:
- injectPrimitiveGetterSetter("Long", LRETURN, LLOAD,
- fieldType, fieldTypeSort, cw, member, isStatic, classNameInternal);
- break;
- case Type.DOUBLE:
- injectPrimitiveGetterSetter("Double", DRETURN, DLOAD,
- fieldType, fieldTypeSort, cw, member, isStatic, classNameInternal);
- break;
- }
- cw.visitEnd();
- return cw.toByteArray();
- }
- private static void injectPrimitiveGetterSetter(String name, int returnValueInstruction, int loadValueInstruction,
- Type fieldType, int fieldTypeSort, ClassWriter cw,
- java.lang.reflect.Field field,
- boolean isStatic, String classNameInternal) {
- final String typeNameInternal = fieldType.getDescriptor();
- MethodVisitor mv;
- {
- mv = cw.visitMethod(ACC_PUBLIC, "get" + name, "(Ljava/lang/Object;)" + typeNameInternal, null, null);
- mv.visitCode();
- if (!isStatic) {
- mv.visitVarInsn(ALOAD, 1);
- mv.visitTypeInsn(CHECKCAST, classNameInternal);
- }
- mv.visitFieldInsn(isStatic ? GETSTATIC : GETFIELD, classNameInternal, field.getName(), typeNameInternal);
- mv.visitInsn(returnValueInstruction);
- mv.visitMaxs(0, 0);
- mv.visitEnd();
- }
- {
- mv = cw.visitMethod(ACC_PUBLIC, "set" + name, "(Ljava/lang/Object;" + typeNameInternal + ")V", null, null);
- mv.visitCode();
- if (!isStatic) {
- mv.visitVarInsn(ALOAD, 1);
- mv.visitTypeInsn(CHECKCAST, classNameInternal);
- }
- mv.visitVarInsn(loadValueInstruction,2);
- mv.visitFieldInsn(isStatic ? PUTSTATIC : PUTFIELD, classNameInternal, field.getName(), typeNameInternal);
- mv.visitInsn(RETURN);
- mv.visitMaxs(0, 0);
- mv.visitEnd();
- }
- }
- private static byte[] createAccessor(String accessClassName, java.lang.reflect.Method member) {
- String className = member.getDeclaringClass().getName();
- String classNameInternal = internalClassName(className);
- ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
- injectConstructor(accessClassName, Method.class, cw);
- {
- MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "invoke",
- "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", null, null);
- mv.visitCode();
- boolean isStatic = Modifier.isStatic(member.getModifiers());
- if (!isStatic) {
- mv.visitVarInsn(ALOAD, 1);
- mv.visitTypeInsn(CHECKCAST, classNameInternal);
- }
- StringBuilder buffer = new StringBuilder(128);
- buffer.setLength(0);
- buffer.append('(');
- Class[] paramTypes = member.getParameterTypes();
- injectVarArgs(mv, buffer, paramTypes, 2);
- buffer.append(')');
- buffer.append(Type.getDescriptor(member.getReturnType()));
- mv.visitMethodInsn(isStatic ? INVOKESTATIC : INVOKEVIRTUAL, classNameInternal, member.getName(), buffer.toString());
- int retValType = Type.getType(member.getReturnType()).getSort();
- injectBoxing(mv, retValType);
- mv.visitInsn(ARETURN);
- mv.visitMaxs(0, 0);
- mv.visitEnd();
- }
- cw.visitEnd();
- return cw.toByteArray();
- }
- private static void injectBoxing(MethodVisitor mv, int retValType) {
- switch (retValType) {
- case Type.VOID:
- mv.visitInsn(ACONST_NULL);
- break;
- case Type.BOOLEAN:
- mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
- break;
- case Type.BYTE:
- mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
- break;
- case Type.CHAR:
- mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
- break;
- case Type.SHORT:
- mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
- break;
- case Type.INT:
- mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
- break;
- case Type.FLOAT:
- mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
- break;
- case Type.LONG:
- mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
- break;
- case Type.DOUBLE:
- mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
- break;
- }
- }
- private static void injectVarArgs(MethodVisitor mv, StringBuilder buffer, Class[] paramTypes, int varArgsPosition) {
- for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
- mv.visitVarInsn(ALOAD, varArgsPosition);
- mv.visitIntInsn(BIPUSH, paramIndex);
- mv.visitInsn(AALOAD);
- Type paramType = Type.getType(paramTypes[paramIndex]);
- injectUnBoxing(mv, paramType);
- buffer.append(paramType.getDescriptor());
- }
- }
- private static void injectUnBoxing(MethodVisitor mv, Type paramType) {
- int paramTypeSort = paramType.getSort();
- switch (paramTypeSort) {
- case Type.BOOLEAN:
- mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
- break;
- case Type.BYTE:
- mv.visitTypeInsn(CHECKCAST, "java/lang/Number");
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "byteValue", "()B");
- break;
- case Type.CHAR:
- mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
- break;
- case Type.SHORT:
- mv.visitTypeInsn(CHECKCAST, "java/lang/Number");
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "shortValue", "()S");
- break;
- case Type.INT:
- mv.visitTypeInsn(CHECKCAST, "java/lang/Number");
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I");
- break;
- case Type.FLOAT:
- mv.visitTypeInsn(CHECKCAST, "java/lang/Number");
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "floatValue", "()F");
- break;
- case Type.LONG:
- mv.visitTypeInsn(CHECKCAST, "java/lang/Number");
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "longValue", "()J");
- break;
- case Type.DOUBLE:
- mv.visitTypeInsn(CHECKCAST, "java/lang/Number");
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "doubleValue", "()D");
- break;
- case Type.ARRAY:
- mv.visitTypeInsn(CHECKCAST, paramType.getDescriptor());
- break;
- case Type.OBJECT:
- mv.visitTypeInsn(CHECKCAST, paramType.getInternalName());
- break;
- }
- }
- private static void injectConstructor(String accessClassName, Class<?> baseClass, ClassWriter cw) {
- String accessClassNameInternal = internalClassName(accessClassName);
- String baseClassNameInternal = internalClassName(baseClass.getName());
- cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, baseClassNameInternal,
- null);
- {
- MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
- mv.visitCode();
- mv.visitVarInsn(ALOAD, 0);
- mv.visitMethodInsn(INVOKESPECIAL, baseClassNameInternal, "<init>", "()V");
- mv.visitInsn(RETURN);
- mv.visitMaxs(0, 0);
- mv.visitEnd();
- }
- }
- public static abstract class Constructor {
- private java.lang.reflect.Constructor<?> _member;
- public java.lang.reflect.Constructor<?> member() {
- return _member;
- }
- public final Object newInstance() {
- return newInstance(EMPTY_VARARGS);
- }
- public abstract Object newInstance(Object... args);
- @Override
- public String toString() {
- return member().toString();
- }
- }
- public static abstract class Method {
- private java.lang.reflect.Method _member;
- public java.lang.reflect.Method member() {
- return _member;
- }
- public final Object invokeStatic() {
- return invoke(null, EMPTY_VARARGS);
- }
- public final Object invokeStatic(Object... args) {
- return invoke(null, args);
- }
- public final Object invoke(Object instance) {
- return invoke(instance, EMPTY_VARARGS);
- }
- public abstract Object invoke(Object instance, Object... args);
- @Override
- public String toString() {
- return member().toString();
- }
- }
- public static abstract class Field {
- abstract public void set(Object instance, Object value);
- public void setBoolean(Object instance, boolean value) {
- throw new UnsupportedOperationException();
- }
- public void setByte(Object instance, byte value) {
- throw new UnsupportedOperationException();
- }
- public void setShort(Object instance, short value) {
- throw new UnsupportedOperationException();
- }
- public void setInt(Object instance, int value) {
- throw new UnsupportedOperationException();
- }
- public void setLong(Object instance, long value) {
- throw new UnsupportedOperationException();
- }
- public void setDouble(Object instance, double value) {
- throw new UnsupportedOperationException();
- }
- public void setFloat(Object instance, float value) {
- throw new UnsupportedOperationException();
- }
- public void setChar(Object instance, char value) {
- throw new UnsupportedOperationException();
- }
- abstract public Object get(Object instance);
- public char getChar(Object instance) {
- throw new UnsupportedOperationException();
- }
- public boolean getBoolean(Object instance) {
- throw new UnsupportedOperationException();
- }
- public byte getByte(Object instance) {
- throw new UnsupportedOperationException();
- }
- public short getShort(Object instance) {
- throw new UnsupportedOperationException();
- }
- public int getInt(Object instance) {
- throw new UnsupportedOperationException();
- }
- public long getLong(Object instance) {
- throw new UnsupportedOperationException();
- }
- public double getDouble(Object instance) {
- throw new UnsupportedOperationException();
- }
- public float getFloat(Object instance) {
- throw new UnsupportedOperationException();
- }
- private java.lang.reflect.Field _member;
- public java.lang.reflect.Field member() {
- return _member;
- }
- @Override
- public String toString() {
- return member().toString();
- }
- }
- /*************************************************************
- * taken from https://github.com/EsotericSoftware/reflectasm
- */
- @SuppressWarnings("unchecked")
- private static class AccessClassLoader_2 extends ClassLoader {
- static private final ArrayList<AccessClassLoader_2> accessClassLoaders = new ArrayList();
- static AccessClassLoader_2 get(Class type) {
- ClassLoader parent = type.getClassLoader();
- synchronized (accessClassLoaders) {
- //noinspection ForLoopReplaceableByForEach
- for (int i = 0, n = accessClassLoaders.size(); i < n; i++) {
- AccessClassLoader_2 accessClassLoader = accessClassLoaders.get(i);
- if (accessClassLoader.getParent() == parent) return accessClassLoader;
- }
- AccessClassLoader_2 accessClassLoader = new AccessClassLoader_2(parent);
- accessClassLoaders.add(accessClassLoader);
- return accessClassLoader;
- }
- }
- private AccessClassLoader_2(ClassLoader parent) {
- super(parent);
- }
- private static final Class[] wellKnownClasses = new Class[]{
- FastReflection.class,
- FastReflection.Constructor.class,
- FastReflection.Method.class,
- FastReflection.Field.class
- };
- protected synchronized java.lang.Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
- // These classes come from the classloader that loaded AccessClassLoader_2.
- for (Class wellKnownClass : wellKnownClasses) {
- if (name.equals(wellKnownClass.getName())) return wellKnownClass;
- }
- // All other classes come from the classloader that loaded the type we are accessing.
- return super.loadClass(name, resolve);
- }
- Class<?> defineClass(String name, byte[] bytes) throws ClassFormatError {
- try {
- // Attempt to load the access class in the same loader, which makes protected and default access members accessible.
- java.lang.reflect.Method method = ClassLoader.class.getDeclaredMethod("defineClass", new Class[]{String.class, byte[].class, int.class,
- int.class});
- method.setAccessible(true);
- //noinspection RedundantArrayCreation,UnnecessaryBoxing
- return (Class) method.invoke(getParent(), new Object[]{name, bytes, Integer.valueOf(0), Integer.valueOf(bytes.length)});
- } catch (Exception ignored) {
- }
- return defineClass(name, bytes, 0, bytes.length);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement