Advertisement
Guest User

FastReflection.java

a guest
Mar 6th, 2014
190
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 24.99 KB | None | 0 0
  1. /******************************************************************************
  2.  * Inspired by https://github.com/EsotericSoftware/reflectasm
  3.  * the main idea is to take away introspection from ReflectASM
  4.  *
  5.  * You must obtain reflection member (Constructor,Method or Field)
  6.  * yourself then pass it to FastReflection.of() method to obtain
  7.  * code generated access-object...
  8.  *
  9.  * Also (since it operate per-member basis) it takes away ugly switches
  10.  * into generated bytecode, supports parametrized constructors and
  11.  * static fields/members...
  12.  */
  13. package com.esotericsoftware.reflectasm.dimzon;
  14.  
  15. import org.objectweb.asm.ClassWriter;
  16. import org.objectweb.asm.MethodVisitor;
  17. import org.objectweb.asm.Type;
  18.  
  19. import java.io.File;
  20. import java.lang.reflect.Member;
  21. import java.lang.reflect.Modifier;
  22. import java.nio.charset.StandardCharsets;
  23. import java.security.MessageDigest;
  24. import java.security.NoSuchAlgorithmException;
  25. import java.util.ArrayList;
  26. import java.util.Objects;
  27.  
  28. import static org.objectweb.asm.Opcodes.*;
  29.  
  30. @SuppressWarnings("UnusedDeclaration")
  31. public final class FastReflection {
  32.     public static void main(String[] args) throws Throwable {
  33.         Class ps = System.out.getClass();
  34.         java.lang.reflect.Method psMethod = ps.getMethod("println", Object.class);
  35.         Method println = of(psMethod);
  36.         println.invoke(System.out, "System.out");
  37.         println.invoke(System.err, "System.err");
  38.         java.lang.reflect.Method nanoTime = System.class.getMethod("nanoTime");
  39.         println.invoke(System.out, of(nanoTime).invokeStatic());
  40.         println.invoke(System.err, of(nanoTime).invokeStatic());
  41.  
  42.         java.lang.reflect.Constructor<File> fileConstructor = File.class.getConstructor(String.class);
  43.         Object o = of(fileConstructor).newInstance("c:\\bla.txt");
  44.         System.out.println(o);
  45.  
  46.         java.lang.reflect.Field field = System.class.getField("out");
  47.         Object o1 = of(field).get(null);
  48.         System.out.println(o1);
  49.     }
  50.  
  51.  
  52.     private static final Object[] EMPTY_VARARGS = new Object[0];
  53.     private static final ThreadLocal<MessageDigest> md5 = new ThreadLocal<MessageDigest>() {
  54.         @Override
  55.         protected MessageDigest initialValue() {
  56.             try {
  57.                 return MessageDigest.getInstance("MD5");
  58.             } catch (NoSuchAlgorithmException nsae) {
  59.                 throw new RuntimeException(nsae);
  60.             }
  61.         }
  62.     };
  63.  
  64.  
  65.     private static String memberAccessClassName(Member member) {
  66.         byte[] md5Bytes = md5.get().digest(member.toString().getBytes(StandardCharsets.UTF_8));
  67.         String sign = member.getDeclaringClass().getName()
  68.                 + "__"
  69.                 + javax.xml.bind.DatatypeConverter.printHexBinary(md5Bytes);
  70.         if (sign.startsWith("java.")) sign = "reflectasm." + sign;
  71.         return sign;
  72.     }
  73.  
  74.     public static Constructor of(java.lang.reflect.Constructor ctor) {
  75.         Objects.requireNonNull(ctor);
  76.         Class accessClass;
  77.         String accessClassName = memberAccessClassName(ctor);
  78.         AccessClassLoader_2 loader = AccessClassLoader_2.get(ctor.getDeclaringClass());
  79.         //noinspection SynchronizationOnLocalVariableOrMethodParameter
  80.         synchronized (loader) {
  81.             try {
  82.                 accessClass = loader.loadClass(accessClassName);
  83.             } catch (ClassNotFoundException ignored) {
  84.                 byte[] byteCode = createAccessor(accessClassName, ctor);
  85.                 accessClass = loader.defineClass(accessClassName, byteCode);
  86.             }
  87.         }
  88.         try {
  89.             Constructor m = (Constructor) accessClass.newInstance();
  90.             m._member = ctor;
  91.             return m;
  92.         } catch (Throwable e) {
  93.             throw new RuntimeException("Error constructing constructor access class: " + accessClassName, e);
  94.         }
  95.     }
  96.  
  97.  
  98.     public static Method of(java.lang.reflect.Method method) {
  99.         Objects.requireNonNull(method);
  100.         Class accessClass;
  101.         String accessClassName = memberAccessClassName(method);
  102.         AccessClassLoader_2 loader = AccessClassLoader_2.get(method.getDeclaringClass());
  103.         //noinspection SynchronizationOnLocalVariableOrMethodParameter
  104.         synchronized (loader) {
  105.             try {
  106.                 accessClass = loader.loadClass(accessClassName);
  107.             } catch (ClassNotFoundException ignored) {
  108.                 byte[] byteCode = createAccessor(accessClassName, method);
  109.                 accessClass = loader.defineClass(accessClassName, byteCode);
  110.             }
  111.         }
  112.         try {
  113.             Method m = (Method) accessClass.newInstance();
  114.             m._member = method;
  115.             return m;
  116.         } catch (Throwable e) {
  117.             throw new RuntimeException("Error constructing method access class: " + accessClassName, e);
  118.         }
  119.     }
  120.  
  121.     public static Field of(java.lang.reflect.Field field) {
  122.         Objects.requireNonNull(field);
  123.         Class accessClass;
  124.         String accessClassName = memberAccessClassName(field);
  125.         AccessClassLoader_2 loader = AccessClassLoader_2.get(field.getDeclaringClass());
  126.         //noinspection SynchronizationOnLocalVariableOrMethodParameter
  127.         synchronized (loader) {
  128.             try {
  129.                 accessClass = loader.loadClass(accessClassName);
  130.             } catch (ClassNotFoundException ignored) {
  131.                 byte[] byteCode = createAccessor(accessClassName, field);
  132.                 accessClass = loader.defineClass(accessClassName, byteCode);
  133.             }
  134.         }
  135.         try {
  136.             Field m = (Field) accessClass.newInstance();
  137.             m._member = field;
  138.             return m;
  139.         } catch (Throwable e) {
  140.             throw new RuntimeException("Error constructing field access class: " + accessClassName, e);
  141.         }
  142.     }
  143.  
  144.     private static byte[] createAccessor(String accessClassName, java.lang.reflect.Constructor<?> member) {
  145.         String className = member.getDeclaringClass().getName();
  146.         String classNameInternal = internalClassName(className);
  147.  
  148.         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
  149.  
  150.         injectConstructor(accessClassName, Constructor.class, cw);
  151.         {
  152.             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "newInstance",
  153.                     "([Ljava/lang/Object;)Ljava/lang/Object;", null, null);
  154.             mv.visitCode();
  155.             mv.visitTypeInsn(NEW, classNameInternal);
  156.             mv.visitInsn(DUP);
  157.             StringBuilder buffer = new StringBuilder(128);
  158.             buffer.setLength(0);
  159.             buffer.append('(');
  160.             injectVarArgs(mv, buffer, member.getParameterTypes(), 1);
  161.             buffer.append(")V");
  162.             mv.visitMethodInsn(INVOKESPECIAL, classNameInternal, "<init>", buffer.toString());
  163.             mv.visitInsn(ARETURN);
  164.             mv.visitMaxs(0, 0);
  165.             mv.visitEnd();
  166.         }
  167.         cw.visitEnd();
  168.         return cw.toByteArray();
  169.     }
  170.  
  171.     private static String internalClassName(String classicClassName) {
  172.         return classicClassName.replace('.', '/');
  173.     }
  174.  
  175.     private static byte[] createAccessor(String accessClassName, java.lang.reflect.Field member) {
  176.         String className = member.getDeclaringClass().getName();
  177.         String classNameInternal = internalClassName(className);
  178.         boolean isStatic = Modifier.isStatic(member.getModifiers());
  179.         Class<?> memberType = member.getType();
  180.         Type fieldType = Type.getType(memberType);
  181.         int fieldTypeSort = fieldType.getSort();
  182.  
  183.         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
  184.  
  185.         injectConstructor(accessClassName, Field.class, cw);
  186.         MethodVisitor mv;
  187.         {
  188.             mv = cw.visitMethod(ACC_PUBLIC, "get",
  189.                     "(Ljava/lang/Object;)Ljava/lang/Object;", null, null);
  190.             mv.visitCode();
  191.             if (!isStatic) {
  192.                 mv.visitVarInsn(ALOAD, 1);
  193.                 mv.visitTypeInsn(CHECKCAST, classNameInternal);
  194.             }
  195.             mv.visitFieldInsn(isStatic ? GETSTATIC : GETFIELD, classNameInternal, member.getName(), Type.getDescriptor(memberType));
  196.             injectBoxing(mv, fieldTypeSort);
  197.             mv.visitInsn(ARETURN);
  198.             mv.visitMaxs(0, 0);
  199.             mv.visitEnd();
  200.         }
  201.         {
  202.             mv = cw.visitMethod(ACC_PUBLIC, "set",
  203.                     "(Ljava/lang/Object;Ljava/lang/Object;)V", null, null);
  204.             mv.visitCode();
  205.             if (!isStatic) {
  206.                 mv.visitVarInsn(ALOAD, 1);
  207.                 mv.visitTypeInsn(CHECKCAST, classNameInternal);
  208.             }
  209.             mv.visitVarInsn(ALOAD, 2);
  210.             injectUnBoxing(mv, fieldType);
  211.             mv.visitFieldInsn(isStatic ? PUTSTATIC : PUTFIELD, classNameInternal, member.getName(), fieldType.getDescriptor());
  212.             mv.visitInsn(RETURN);
  213.             mv.visitMaxs(0, 0);
  214.             mv.visitEnd();
  215.         }
  216.         switch (fieldTypeSort) {
  217.             case Type.BOOLEAN:
  218.                 injectPrimitiveGetterSetter("Boolean", IRETURN, ILOAD,
  219.                         fieldType, fieldTypeSort, cw, member, isStatic, classNameInternal);
  220.                 break;
  221.             case Type.BYTE:
  222.                 injectPrimitiveGetterSetter("Byte", IRETURN, ILOAD,
  223.                         fieldType, fieldTypeSort, cw, member, isStatic, classNameInternal);
  224.                 break;
  225.             case Type.CHAR:
  226.                 injectPrimitiveGetterSetter("Char", IRETURN, ILOAD,
  227.                         fieldType, fieldTypeSort, cw, member, isStatic, classNameInternal);
  228.                 break;
  229.             case Type.SHORT:
  230.                 injectPrimitiveGetterSetter("Short", IRETURN, ILOAD,
  231.                         fieldType, fieldTypeSort, cw, member, isStatic, classNameInternal);
  232.                 break;
  233.             case Type.INT:
  234.                 injectPrimitiveGetterSetter("Int", IRETURN, ILOAD,
  235.                         fieldType, fieldTypeSort, cw, member, isStatic, classNameInternal);
  236.                 break;
  237.             case Type.FLOAT:
  238.                 injectPrimitiveGetterSetter("Float", FRETURN, FLOAD,
  239.                         fieldType, fieldTypeSort, cw, member, isStatic, classNameInternal);
  240.  
  241.                 break;
  242.             case Type.LONG:
  243.                 injectPrimitiveGetterSetter("Long", LRETURN, LLOAD,
  244.                         fieldType, fieldTypeSort, cw, member, isStatic, classNameInternal);
  245.                 break;
  246.             case Type.DOUBLE:
  247.                 injectPrimitiveGetterSetter("Double", DRETURN, DLOAD,
  248.                         fieldType, fieldTypeSort, cw, member, isStatic, classNameInternal);
  249.                 break;
  250.         }
  251.         cw.visitEnd();
  252.         return cw.toByteArray();
  253.     }
  254.  
  255.     private static void injectPrimitiveGetterSetter(String name, int returnValueInstruction, int loadValueInstruction,
  256.                                                     Type fieldType, int fieldTypeSort, ClassWriter cw,
  257.                                                     java.lang.reflect.Field field,
  258.                                                     boolean isStatic, String classNameInternal) {
  259.         final String typeNameInternal = fieldType.getDescriptor();
  260.         MethodVisitor mv;
  261.         {
  262.             mv = cw.visitMethod(ACC_PUBLIC, "get" + name, "(Ljava/lang/Object;)" + typeNameInternal, null, null);
  263.             mv.visitCode();
  264.             if (!isStatic) {
  265.                 mv.visitVarInsn(ALOAD, 1);
  266.                 mv.visitTypeInsn(CHECKCAST, classNameInternal);
  267.             }
  268.             mv.visitFieldInsn(isStatic ? GETSTATIC : GETFIELD, classNameInternal, field.getName(), typeNameInternal);
  269.             mv.visitInsn(returnValueInstruction);
  270.             mv.visitMaxs(0, 0);
  271.             mv.visitEnd();
  272.         }
  273.         {
  274.             mv = cw.visitMethod(ACC_PUBLIC, "set" + name, "(Ljava/lang/Object;" + typeNameInternal + ")V", null, null);
  275.             mv.visitCode();
  276.             if (!isStatic) {
  277.                 mv.visitVarInsn(ALOAD, 1);
  278.                 mv.visitTypeInsn(CHECKCAST, classNameInternal);
  279.             }
  280.             mv.visitVarInsn(loadValueInstruction,2);
  281.             mv.visitFieldInsn(isStatic ? PUTSTATIC : PUTFIELD, classNameInternal, field.getName(), typeNameInternal);
  282.             mv.visitInsn(RETURN);
  283.             mv.visitMaxs(0, 0);
  284.             mv.visitEnd();
  285.         }
  286.     }
  287.  
  288.     private static byte[] createAccessor(String accessClassName, java.lang.reflect.Method member) {
  289.         String className = member.getDeclaringClass().getName();
  290.         String classNameInternal = internalClassName(className);
  291.  
  292.         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
  293.         injectConstructor(accessClassName, Method.class, cw);
  294.         {
  295.             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "invoke",
  296.                     "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", null, null);
  297.             mv.visitCode();
  298.             boolean isStatic = Modifier.isStatic(member.getModifiers());
  299.             if (!isStatic) {
  300.                 mv.visitVarInsn(ALOAD, 1);
  301.                 mv.visitTypeInsn(CHECKCAST, classNameInternal);
  302.             }
  303.  
  304.             StringBuilder buffer = new StringBuilder(128);
  305.  
  306.             buffer.setLength(0);
  307.             buffer.append('(');
  308.  
  309.             Class[] paramTypes = member.getParameterTypes();
  310.             injectVarArgs(mv, buffer, paramTypes, 2);
  311.  
  312.             buffer.append(')');
  313.             buffer.append(Type.getDescriptor(member.getReturnType()));
  314.             mv.visitMethodInsn(isStatic ? INVOKESTATIC : INVOKEVIRTUAL, classNameInternal, member.getName(), buffer.toString());
  315.  
  316.             int retValType = Type.getType(member.getReturnType()).getSort();
  317.             injectBoxing(mv, retValType);
  318.  
  319.             mv.visitInsn(ARETURN);
  320.             mv.visitMaxs(0, 0);
  321.             mv.visitEnd();
  322.         }
  323.         cw.visitEnd();
  324.         return cw.toByteArray();
  325.     }
  326.  
  327.     private static void injectBoxing(MethodVisitor mv, int retValType) {
  328.         switch (retValType) {
  329.             case Type.VOID:
  330.                 mv.visitInsn(ACONST_NULL);
  331.                 break;
  332.             case Type.BOOLEAN:
  333.                 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
  334.                 break;
  335.             case Type.BYTE:
  336.                 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
  337.                 break;
  338.             case Type.CHAR:
  339.                 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
  340.                 break;
  341.             case Type.SHORT:
  342.                 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
  343.                 break;
  344.             case Type.INT:
  345.                 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
  346.                 break;
  347.             case Type.FLOAT:
  348.                 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
  349.                 break;
  350.             case Type.LONG:
  351.                 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
  352.                 break;
  353.             case Type.DOUBLE:
  354.                 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
  355.                 break;
  356.         }
  357.     }
  358.  
  359.     private static void injectVarArgs(MethodVisitor mv, StringBuilder buffer, Class[] paramTypes, int varArgsPosition) {
  360.         for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
  361.             mv.visitVarInsn(ALOAD, varArgsPosition);
  362.             mv.visitIntInsn(BIPUSH, paramIndex);
  363.             mv.visitInsn(AALOAD);
  364.             Type paramType = Type.getType(paramTypes[paramIndex]);
  365.  
  366.             injectUnBoxing(mv, paramType);
  367.             buffer.append(paramType.getDescriptor());
  368.         }
  369.     }
  370.  
  371.     private static void injectUnBoxing(MethodVisitor mv, Type paramType) {
  372.         int paramTypeSort = paramType.getSort();
  373.         switch (paramTypeSort) {
  374.             case Type.BOOLEAN:
  375.                 mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
  376.                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
  377.                 break;
  378.             case Type.BYTE:
  379.                 mv.visitTypeInsn(CHECKCAST, "java/lang/Number");
  380.                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "byteValue", "()B");
  381.                 break;
  382.             case Type.CHAR:
  383.                 mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
  384.                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
  385.                 break;
  386.             case Type.SHORT:
  387.                 mv.visitTypeInsn(CHECKCAST, "java/lang/Number");
  388.                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "shortValue", "()S");
  389.                 break;
  390.             case Type.INT:
  391.                 mv.visitTypeInsn(CHECKCAST, "java/lang/Number");
  392.                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I");
  393.                 break;
  394.             case Type.FLOAT:
  395.                 mv.visitTypeInsn(CHECKCAST, "java/lang/Number");
  396.                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "floatValue", "()F");
  397.                 break;
  398.             case Type.LONG:
  399.                 mv.visitTypeInsn(CHECKCAST, "java/lang/Number");
  400.                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "longValue", "()J");
  401.                 break;
  402.             case Type.DOUBLE:
  403.                 mv.visitTypeInsn(CHECKCAST, "java/lang/Number");
  404.                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "doubleValue", "()D");
  405.                 break;
  406.             case Type.ARRAY:
  407.                 mv.visitTypeInsn(CHECKCAST, paramType.getDescriptor());
  408.                 break;
  409.             case Type.OBJECT:
  410.                 mv.visitTypeInsn(CHECKCAST, paramType.getInternalName());
  411.                 break;
  412.         }
  413.     }
  414.  
  415.     private static void injectConstructor(String accessClassName, Class<?> baseClass, ClassWriter cw) {
  416.         String accessClassNameInternal = internalClassName(accessClassName);
  417.         String baseClassNameInternal = internalClassName(baseClass.getName());
  418.         cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, baseClassNameInternal,
  419.                 null);
  420.         {
  421.             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
  422.             mv.visitCode();
  423.             mv.visitVarInsn(ALOAD, 0);
  424.             mv.visitMethodInsn(INVOKESPECIAL, baseClassNameInternal, "<init>", "()V");
  425.             mv.visitInsn(RETURN);
  426.             mv.visitMaxs(0, 0);
  427.             mv.visitEnd();
  428.         }
  429.     }
  430.  
  431.  
  432.     public static abstract class Constructor {
  433.         private java.lang.reflect.Constructor<?> _member;
  434.  
  435.         public java.lang.reflect.Constructor<?> member() {
  436.             return _member;
  437.         }
  438.  
  439.         public final Object newInstance() {
  440.             return newInstance(EMPTY_VARARGS);
  441.         }
  442.  
  443.         public abstract Object newInstance(Object... args);
  444.  
  445.         @Override
  446.         public String toString() {
  447.             return member().toString();
  448.         }
  449.  
  450.     }
  451.  
  452.     public static abstract class Method {
  453.         private java.lang.reflect.Method _member;
  454.  
  455.         public java.lang.reflect.Method member() {
  456.             return _member;
  457.         }
  458.  
  459.         public final Object invokeStatic() {
  460.             return invoke(null, EMPTY_VARARGS);
  461.         }
  462.  
  463.         public final Object invokeStatic(Object... args) {
  464.             return invoke(null, args);
  465.         }
  466.  
  467.         public final Object invoke(Object instance) {
  468.             return invoke(instance, EMPTY_VARARGS);
  469.         }
  470.  
  471.         public abstract Object invoke(Object instance, Object... args);
  472.  
  473.         @Override
  474.         public String toString() {
  475.             return member().toString();
  476.         }
  477.  
  478.     }
  479.  
  480.     public static abstract class Field {
  481.         abstract public void set(Object instance, Object value);
  482.  
  483.         public void setBoolean(Object instance, boolean value) {
  484.             throw new UnsupportedOperationException();
  485.         }
  486.  
  487.         public void setByte(Object instance, byte value) {
  488.             throw new UnsupportedOperationException();
  489.         }
  490.  
  491.         public void setShort(Object instance, short value) {
  492.             throw new UnsupportedOperationException();
  493.         }
  494.  
  495.         public void setInt(Object instance, int value) {
  496.             throw new UnsupportedOperationException();
  497.         }
  498.  
  499.         public void setLong(Object instance, long value) {
  500.             throw new UnsupportedOperationException();
  501.         }
  502.  
  503.         public void setDouble(Object instance, double value) {
  504.             throw new UnsupportedOperationException();
  505.         }
  506.  
  507.         public void setFloat(Object instance, float value) {
  508.             throw new UnsupportedOperationException();
  509.         }
  510.  
  511.         public void setChar(Object instance, char value) {
  512.             throw new UnsupportedOperationException();
  513.         }
  514.  
  515.         abstract public Object get(Object instance);
  516.  
  517.         public char getChar(Object instance) {
  518.             throw new UnsupportedOperationException();
  519.         }
  520.  
  521.         public boolean getBoolean(Object instance) {
  522.             throw new UnsupportedOperationException();
  523.         }
  524.  
  525.         public byte getByte(Object instance) {
  526.             throw new UnsupportedOperationException();
  527.         }
  528.  
  529.         public short getShort(Object instance) {
  530.             throw new UnsupportedOperationException();
  531.         }
  532.  
  533.         public int getInt(Object instance) {
  534.             throw new UnsupportedOperationException();
  535.         }
  536.  
  537.         public long getLong(Object instance) {
  538.             throw new UnsupportedOperationException();
  539.         }
  540.  
  541.         public double getDouble(Object instance) {
  542.             throw new UnsupportedOperationException();
  543.         }
  544.  
  545.         public float getFloat(Object instance) {
  546.             throw new UnsupportedOperationException();
  547.         }
  548.  
  549.         private java.lang.reflect.Field _member;
  550.  
  551.         public java.lang.reflect.Field member() {
  552.             return _member;
  553.         }
  554.  
  555.         @Override
  556.         public String toString() {
  557.             return member().toString();
  558.         }
  559.     }
  560.  
  561.     /*************************************************************
  562.      * taken from https://github.com/EsotericSoftware/reflectasm
  563.      */
  564.     @SuppressWarnings("unchecked")
  565.     private static class AccessClassLoader_2 extends ClassLoader {
  566.         static private final ArrayList<AccessClassLoader_2> accessClassLoaders = new ArrayList();
  567.  
  568.         static AccessClassLoader_2 get(Class type) {
  569.             ClassLoader parent = type.getClassLoader();
  570.             synchronized (accessClassLoaders) {
  571.                 //noinspection ForLoopReplaceableByForEach
  572.                 for (int i = 0, n = accessClassLoaders.size(); i < n; i++) {
  573.                     AccessClassLoader_2 accessClassLoader = accessClassLoaders.get(i);
  574.                     if (accessClassLoader.getParent() == parent) return accessClassLoader;
  575.                 }
  576.                 AccessClassLoader_2 accessClassLoader = new AccessClassLoader_2(parent);
  577.                 accessClassLoaders.add(accessClassLoader);
  578.                 return accessClassLoader;
  579.             }
  580.         }
  581.  
  582.         private AccessClassLoader_2(ClassLoader parent) {
  583.             super(parent);
  584.         }
  585.  
  586.         private static final Class[] wellKnownClasses = new Class[]{
  587.                 FastReflection.class,
  588.                 FastReflection.Constructor.class,
  589.                 FastReflection.Method.class,
  590.                 FastReflection.Field.class
  591.         };
  592.  
  593.         protected synchronized java.lang.Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
  594.             // These classes come from the classloader that loaded AccessClassLoader_2.
  595.             for (Class wellKnownClass : wellKnownClasses) {
  596.                 if (name.equals(wellKnownClass.getName())) return wellKnownClass;
  597.             }
  598.             // All other classes come from the classloader that loaded the type we are accessing.
  599.             return super.loadClass(name, resolve);
  600.         }
  601.  
  602.         Class<?> defineClass(String name, byte[] bytes) throws ClassFormatError {
  603.             try {
  604.                 // Attempt to load the access class in the same loader, which makes protected and default access members accessible.
  605.                 java.lang.reflect.Method method = ClassLoader.class.getDeclaredMethod("defineClass", new Class[]{String.class, byte[].class, int.class,
  606.                         int.class});
  607.                 method.setAccessible(true);
  608.                 //noinspection RedundantArrayCreation,UnnecessaryBoxing
  609.                 return (Class) method.invoke(getParent(), new Object[]{name, bytes, Integer.valueOf(0), Integer.valueOf(bytes.length)});
  610.             } catch (Exception ignored) {
  611.             }
  612.             return defineClass(name, bytes, 0, bytes.length);
  613.         }
  614.     }
  615.  
  616. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement