All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springsource.loaded.SystemClassReflectionRewriter Maven / Gradle / Ivy

There is a newer version: 1.2.8.RELEASE
Show newest version
/*
 * Copyright 2010-2012 VMware and contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springsource.loaded;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

/**
 * This is a special rewriter that should be used on system classes that are using reflection. These classes are loader above the
 * agent code and so cannot use the agent code directly (they can't see the classes). In these situations we will do some rewriting
 * that will only use other system types. How can that work? Well the affected types are modified to expose a static field (per
 * reflective API used), these static fields are set by springloaded during later startup and then are available for access from the
 * rewritten system class code.
 * 

* There is a null check in the injected method for cases where everything runs even sooner than can be plugged by SpringLoaded. *

* The following are implemented so far: * *

* Due to ReflectionNavigator: *

    *
  • getDeclaredFields *
  • getDeclaredField *
  • getField *
  • getModifiers *
  • getDeclaredConstructor *
  • getDeclaredMethods *
  • getDeclaredMethod
  • *

    * Due to ProxyGenerator *

      *
    • getMethods *
    * *

    * This class modifiers the calls to the reflective APIs, adds the fields and helper methods. The wiring of the SpringLoaded * reflectiveinterceptor into types affected by this rewriter is currently done in SpringLoadedPreProcessor. * * @author Andy Clement * @since 0.7.3 */ public class SystemClassReflectionRewriter { private static Logger log = Logger.getLogger(SystemClassReflectionRewriter.class.getName()); public static RewriteResult rewrite(String slashedClassName, byte[] bytes) { if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) { log.info("SystemClassReflectionRewriter running for " + slashedClassName); } ClassReader fileReader = new ClassReader(bytes); RewriteClassAdaptor classAdaptor = new RewriteClassAdaptor(); // TODO always skip frames? or just for javassist things? fileReader.accept(classAdaptor, ClassReader.SKIP_FRAMES); return new RewriteResult(classAdaptor.getBytes(), classAdaptor.getBits()); } public static class RewriteResult implements Constants { public final byte[] bytes; // These bits describe which kinds of reflective things were done in the // type - and so which fields (of the __sl variety) need filling in. For example, // if the JLC_GETDECLAREDFIELDS bit is set, the field __sljlcgdfs must be set public final int bits; public RewriteResult(byte[] bytes, int bits) { this.bytes = bytes; this.bits = bits; } public String summarize() { StringBuilder s = new StringBuilder(); s.append((bits & JLC_GETDECLAREDCONSTRUCTOR) != 0 ? "getDeclaredConstructor()" : ""); s.append((bits & JLC_GETCONSTRUCTOR) != 0 ? "getConstructor()" : ""); s.append((bits & JLC_GETMODIFIERS) != 0 ? "getModifiers()" : ""); s.append((bits & JLC_GETDECLAREDFIELDS) != 0 ? "getDeclaredFields() " : ""); s.append((bits & JLC_GETDECLAREDFIELD) != 0 ? "getDeclaredField() " : ""); s.append((bits & JLC_GETFIELD) != 0 ? "getField() " : ""); s.append((bits & JLC_GETDECLAREDMETHODS) != 0 ? "getDeclaredMethods() " : ""); s.append((bits & JLC_GETDECLAREDMETHOD) != 0 ? "getDeclaredMethod() " : ""); s.append((bits & JLC_GETMETHOD) != 0 ? "getMethod() " : ""); s.append((bits & JLC_GETMETHODS) != 0 ? "getMethods() " : ""); return s.toString().trim(); } } static class RewriteClassAdaptor extends ClassAdapter implements Constants { private ClassWriter cw; int bits = 0x0000; private String classname; // enum SpecialRewrite { NotSpecial, java_io_ObjectStreamClass_2 }; // private SpecialRewrite special = SpecialRewrite.NotSpecial; // TODO [perf] lookup like this really the fastest way? private static boolean isInterceptable(String owner, String methodName) { String s = new StringBuilder(owner).append(".").append(methodName).toString(); return MethodInvokerRewriter.RewriteClassAdaptor.intercepted.contains(s); } public RewriteClassAdaptor() { // TODO should it also compute frames? super(new ClassWriter(ClassWriter.COMPUTE_MAXS)); cw = (ClassWriter) cv; } public byte[] getBytes() { byte[] bytes = cw.toByteArray(); return bytes; } public int getBits() { return bits; } @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { super.visit(version, access, name, signature, superName, interfaces); this.classname = name; // if (classname.equals("java/io/ObjectStreamClass$2")) { // special = SpecialRewrite.java_io_ObjectStreamClass_2; // } } @Override public MethodVisitor visitMethod(int flags, String name, String descriptor, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(flags, name, descriptor, signature, exceptions); return new RewritingMethodAdapter(mv); } @Override public void visitEnd() { addExtraMethodsAndFields(); super.visitEnd(); } private void addExtraMethodsAndFields() { if ((bits & JLC_GETDECLAREDFIELDS) != 0) { SystemClassReflectionGenerator.generateJLCGDFS(cw, classname); } if ((bits & JLC_GETDECLAREDFIELD) != 0) { SystemClassReflectionGenerator.generateJLC(cw, classname, "getDeclaredField"); } if ((bits & JLC_GETFIELD) != 0) { SystemClassReflectionGenerator.generateJLC(cw, classname, "getField"); } if ((bits & JLC_GETDECLAREDMETHODS) != 0) { SystemClassReflectionGenerator.generateJLCGetXXXMethods(cw, classname, "getDeclaredMethods"); } if ((bits & JLC_GETDECLAREDMETHOD) != 0) { SystemClassReflectionGenerator.generateJLCMethod(cw, classname, "getDeclaredMethod"); } if ((bits & JLC_GETMETHOD) != 0) { SystemClassReflectionGenerator.generateJLCMethod(cw, classname, "getMethod"); } if ((bits & JLC_GETMODIFIERS) != 0) { SystemClassReflectionGenerator.generateJLCGMODS(cw, classname); } if ((bits & JLC_GETDECLAREDCONSTRUCTOR) != 0) { SystemClassReflectionGenerator.generateJLCGDC(cw, classname); } if ((bits & JLC_GETMETHODS) != 0) { SystemClassReflectionGenerator.generateJLCGetXXXMethods(cw, classname, "getMethods"); } if ((bits & JLC_GETCONSTRUCTOR) != 0) { SystemClassReflectionGenerator.generateJLCGC(cw, classname); } } class RewritingMethodAdapter extends MethodAdapter implements Opcodes, Constants { public RewritingMethodAdapter(MethodVisitor mv) { super(mv); } /** * The big method for intercepting reflection. It is passed what the original code is trying to do (which method it is * calling) and decides: *

      *
    • whether to rewrite it *
    • what method should be called instead *
    * * @return true if the call was modified/intercepted */ private boolean interceptReflection(String owner, String name, String desc) { if (isInterceptable(owner, name)) { return callReflectiveInterceptor(owner, name, desc, mv); } return false; } int unitializedObjectsCount = 0; @Override public void visitTypeInsn(final int opcode, final String type) { if (opcode == NEW) { unitializedObjectsCount++; } super.visitTypeInsn(opcode, type); } @Override public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { if (!GlobalConfiguration.interceptReflection || rewriteReflectiveCall(opcode, owner, name, desc)) { return; } if (opcode == INVOKESPECIAL) { unitializedObjectsCount--; } // if (special!=SpecialRewrite.NotSpecial) { // // Special cases: // if (special==SpecialRewrite.java_io_ObjectStreamClass_2) { // // The class java.io.ObjectStreamClass is loaded too early for us to modify and yet it uses reflection. // // That means we need to modify calls to that class instead. // // // The anonymous inner type $2 makes a call to // // 66: invokestatic #10; //Method java/io/ObjectStreamClass.access$700:(Ljava/lang/Class;)Ljava/lang/Long; // // which is the accessor method for the private method 'Long getDeclaredSUID()' in ObjectStreamClass. Redirect this // // method to a helper that can retrieve the suid and be rewritten. // // TODO skip descriptor check, surely name is enough? //// if (owner.equals("java/io/ObjectStreamClass") && name.equals("access$700") && desc.equals("(Ljava/lang/Class;)Ljava/lang/Long;")) { //// // 1. retrieve the serialVersionUID field //// mv.visitLdcInsn("serialVersionUID"); //// bits|=JLC_GETDECLAREDFIELD; //// mv.visitMethodInsn(INVOKESTATIC,classname, jlcgdf, jlcgdfDescriptor); //// //// //// } ////// private static Long getDeclaredSUID(Class cl) { ////// try { ////// Field f = cl.getDeclaredField("serialVersionUID"); ////// int mask = Modifier.STATIC | Modifier.FINAL; ////// if ((f.getModifiers() & mask) == mask) { ////// f.setAccessible(true); ////// return Long.valueOf(f.getLong(null)); ////// } ////// } catch (Exception ex) { ////// } ////// return null; ////// } // } // } super.visitMethodInsn(opcode, owner, name, desc); } /** * Determine if a method call is a reflective call and an attempt should be made to rewrite it. * * @return true if the call was rewritten */ private boolean rewriteReflectiveCall(int opcode, String owner, String name, String desc) { if (owner.length() > 10 && owner.charAt(8) == 'g' && (owner.startsWith("java/lang/reflect/") || owner.equals("java/lang/Class"))) { boolean rewritten = interceptReflection(owner, name, desc); if (rewritten) { return true; } } return false; } private boolean callReflectiveInterceptor(String owner, String name, String desc, MethodVisitor mv) { if (owner.equals("java/lang/Class")) { if (name.equals("getDeclaredFields")) { // stack on arrival: bits |= JLC_GETDECLAREDFIELDS; mv.visitMethodInsn(INVOKESTATIC, classname, jlcgdfs, jlcgdfsDescriptor); return true; } else if (name.equals("getDeclaredField")) { // stack on arrival: bits |= JLC_GETDECLAREDFIELD; mv.visitMethodInsn(INVOKESTATIC, classname, jlcgdf, jlcgdfDescriptor); return true; } else if (name.equals("getField")) { // stack on arrival: bits |= JLC_GETFIELD; mv.visitMethodInsn(INVOKESTATIC, classname, jlcgf, jlcgfDescriptor); return true; } else if (name.equals("getDeclaredMethods")) { // stack on arrival: bits |= JLC_GETDECLAREDMETHODS; mv.visitMethodInsn(INVOKESTATIC, classname, jlcgdms, jlcgdmsDescriptor); return true; } else if (name.equals("getDeclaredMethod")) { // stack on arrival: bits |= JLC_GETDECLAREDMETHOD; mv.visitMethodInsn(INVOKESTATIC, classname, jlcgdm, jlcgdmDescriptor); return true; } else if (name.equals("getMethod")) { // stack on arrival: bits |= JLC_GETMETHOD; mv.visitMethodInsn(INVOKESTATIC, classname, jlcgm, jlcgmDescriptor); return true; } else if (name.equals("getDeclaredConstructor")) { // stack on arrival: bits |= JLC_GETDECLAREDCONSTRUCTOR; mv.visitMethodInsn(INVOKESTATIC, classname, jlcgdc, jlcgdcDescriptor); return true; } else if (name.equals("getConstructor")) { // stack on arrival: bits |= JLC_GETCONSTRUCTOR; mv.visitMethodInsn(INVOKESTATIC, classname, jlcgc, jlcgcDescriptor); return true; } else if (name.equals("getModifiers")) { // stack on arrival: bits |= JLC_GETMODIFIERS; mv.visitMethodInsn(INVOKESTATIC, classname, jlcgmods, jlcgmodsDescriptor); return true; } else if (name.equals("getMethods")) { // stack on arrival: bits |= JLC_GETMETHODS; mv.visitMethodInsn(INVOKESTATIC, classname, jlcgms, jlcgmsDescriptor); return true; } else if (name.equals("newInstance")) { // TODO determine if this actually needs rewriting? Just catching in this if clause to avoid the message return false; } } else if (owner.equals("java/lang/reflect/Constructor")) { if (name.equals("newInstance")) { // catching to avoid message // seen: in Proxy Constructor.newInstance() is used on the newly created proxy class - we don't need to intercept that return false; } } System.err.println("!!! SystemClassReflectionRewriter: nyi for " + owner + "." + name); return false; //throw new IllegalStateException("nyi for " + owner + "." + name); } } } } /** * This helper class will generate the fields/methods in the system classes that are being rewritten. */ class SystemClassReflectionGenerator implements Constants { // public static Method __sljlcgdfs; // @SuppressWarnings("unused") // private static Field[] __sljlcgdfs(Class clazz) { // if (__sljlcgdfs == null) { // return clazz.getDeclaredFields(); // } // try { // return (Field[]) __sljlcgdfs.invoke(null, clazz); // } catch (Exception e) { // return null; // } // } // public static Method __sljlcgdms; // @SuppressWarnings("unused") // private static Method[] __sljlcgdms(Class clazz) { // if (__sljlcgdms == null) { // return clazz.getDeclaredMethods(); // } // try { // return (Method[]) __sljlcgdms.invoke(null, clazz); // } catch (Exception e) { // return null; // } // } // public static Method __sljlcgdf; // @SuppressWarnings("unused") // private static Field __sljlcgdf(Class clazz, String fieldname) throws NoSuchFieldException { // if (__sljlcgdf == null) { // return clazz.getDeclaredField(fieldname); // } // try { // return (Field) __sljlcgdf.invoke(null, clazz, fieldname); // } catch (InvocationTargetException ite) { // if (ite.getCause() instanceof NoSuchFieldException) { // throw (NoSuchFieldException) ite.getCause(); // } // } catch (Exception e) { // } // return null; // } // public static Method __sljlcgdm; // // @SuppressWarnings("unused") // private static Method __sljlcgdm(Class clazz, String methodname, Class... parameterTypes) throws NoSuchMethodException { // if (__sljlcgdm == null) { // return clazz.getDeclaredMethod(methodname, parameterTypes); // } // try { // // if (parameterTypes == null) { // return (Method) __sljlcgdm.invoke(null, clazz, methodname, parameterTypes); // // } else { // // Object[] params = new Object[2 + parameterTypes.length]; // // System.arraycopy(parameterTypes, 0, params, 2, parameterTypes.length); // // params[0] = clazz; // // params[1] = methodname; // // return (Method) __sljlcgdm.invoke(null, clazz, methodname, parameterTypes); // // } // } catch (InvocationTargetException ite) { // ite.printStackTrace(); // if (ite.getCause() instanceof NoSuchMethodException) { // throw (NoSuchMethodException) ite.getCause(); // } // } catch (Exception e) { // e.printStackTrace(); // } // return null; // } // public static Method __sljlcgdc; // // @SuppressWarnings("unused") // private static Constructor __sljlcgdc(Class clazz, Class... parameterTypes) throws NoSuchMethodException { // if (__sljlcgdc == null) { // return clazz.getDeclaredConstructor(parameterTypes); // } // try { // return (Constructor) __sljlcgdc.invoke(null, clazz, parameterTypes); // } catch (InvocationTargetException ite) { // ite.printStackTrace(); // if (ite.getCause() instanceof NoSuchMethodException) { // throw (NoSuchMethodException) ite.getCause(); // } // } catch (Exception e) { // e.printStackTrace(); // } // return null; // } // public static Method __sljlcgmods; // // @SuppressWarnings("unused") // private static int __sljlcgmods(Class clazz) { // if (__sljlcgmods == null) { // return clazz.getModifiers(); // } // try { // return (Integer) __sljlcgmods.invoke(null, clazz); // } catch (Exception e) { // e.printStackTrace(); // return 0; // } // } public static void generateJLCGMODS(ClassWriter cw, String classname) { FieldVisitor fv = cw.visitField(ACC_PUBLIC + ACC_STATIC, "__sljlcgmods", "Ljava/lang/reflect/Method;", null, null); fv.visitEnd(); MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC, "__sljlcgmods", "(Ljava/lang/Class;)I", "(Ljava/lang/Class<*>;)I", null); mv.visitCode(); Label l0 = new Label(); Label l1 = new Label(); Label l2 = new Label(); mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Exception"); Label l3 = new Label(); mv.visitLabel(l3); mv.visitFieldInsn(GETSTATIC, classname, "__sljlcgmods", "Ljava/lang/reflect/Method;"); mv.visitJumpInsn(IFNONNULL, l0); Label l4 = new Label(); mv.visitLabel(l4); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getModifiers", "()I"); mv.visitInsn(IRETURN); mv.visitLabel(l0); mv.visitFieldInsn(GETSTATIC, classname, "__sljlcgmods", "Ljava/lang/reflect/Method;"); mv.visitInsn(ACONST_NULL); mv.visitInsn(ICONST_1); mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(AASTORE); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I"); mv.visitLabel(l1); mv.visitInsn(IRETURN); mv.visitLabel(l2); mv.visitVarInsn(ASTORE, 1); Label l5 = new Label(); mv.visitLabel(l5); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Exception", "printStackTrace", "()V"); Label l6 = new Label(); mv.visitLabel(l6); mv.visitInsn(ICONST_0); mv.visitInsn(IRETURN); Label l7 = new Label(); mv.visitLabel(l7); // mv.visitLocalVariable("clazz", "Ljava/lang/Class;", "Ljava/lang/Class<*>;", l3, l7, 0); // mv.visitLocalVariable("e", "Ljava/lang/Exception;", null, l5, l7, 1); mv.visitMaxs(6, 2); mv.visitEnd(); } public static void generateJLCGDC(ClassWriter cw, String classname) { FieldVisitor fv = cw.visitField(ACC_PUBLIC + ACC_STATIC, "__sljlcgdc", "Ljava/lang/reflect/Method;", null, null); fv.visitEnd(); MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_VARARGS, "__sljlcgdc", "(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/reflect/Constructor;", null, new String[] { "java/lang/NoSuchMethodException" }); mv.visitCode(); Label l0 = new Label(); Label l1 = new Label(); Label l2 = new Label(); mv.visitTryCatchBlock(l0, l1, l2, "java/lang/reflect/InvocationTargetException"); Label l3 = new Label(); mv.visitTryCatchBlock(l0, l1, l3, "java/lang/Exception"); Label l4 = new Label(); mv.visitLabel(l4); mv.visitFieldInsn(GETSTATIC, classname, "__sljlcgdc", "Ljava/lang/reflect/Method;"); mv.visitJumpInsn(IFNONNULL, l0); Label l5 = new Label(); mv.visitLabel(l5); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getDeclaredConstructor", "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;"); mv.visitInsn(ARETURN); mv.visitLabel(l0); mv.visitFieldInsn(GETSTATIC, classname, "__sljlcgdc", "Ljava/lang/reflect/Method;"); mv.visitInsn(ACONST_NULL); mv.visitInsn(ICONST_2); mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(AASTORE); mv.visitInsn(DUP); mv.visitInsn(ICONST_1); mv.visitVarInsn(ALOAD, 1); mv.visitInsn(AASTORE); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); mv.visitTypeInsn(CHECKCAST, "java/lang/reflect/Constructor"); mv.visitLabel(l1); mv.visitInsn(ARETURN); mv.visitLabel(l2); mv.visitVarInsn(ASTORE, 2); Label l6 = new Label(); mv.visitLabel(l6); mv.visitVarInsn(ALOAD, 2); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "printStackTrace", "()V"); Label l7 = new Label(); mv.visitLabel(l7); mv.visitVarInsn(ALOAD, 2); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "getCause", "()Ljava/lang/Throwable;"); mv.visitTypeInsn(INSTANCEOF, "java/lang/NoSuchMethodException"); Label l8 = new Label(); mv.visitJumpInsn(IFEQ, l8); Label l9 = new Label(); mv.visitLabel(l9); mv.visitVarInsn(ALOAD, 2); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "getCause", "()Ljava/lang/Throwable;"); mv.visitTypeInsn(CHECKCAST, "java/lang/NoSuchMethodException"); mv.visitInsn(ATHROW); mv.visitLabel(l3); mv.visitVarInsn(ASTORE, 2); Label l10 = new Label(); mv.visitLabel(l10); // mv.visitVarInsn(ALOAD, 2); // mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Exception", "printStackTrace", "()V"); mv.visitLabel(l8); mv.visitInsn(ACONST_NULL); mv.visitInsn(ARETURN); Label l11 = new Label(); mv.visitLabel(l11); // mv.visitLocalVariable("clazz", "Ljava/lang/Class;", "Ljava/lang/Class<*>;", l4, l11, 0); // mv.visitLocalVariable("parameterTypes", "[Ljava/lang/Class;", null, l4, l11, 1); // mv.visitLocalVariable("ite", "Ljava/lang/reflect/InvocationTargetException;", null, l6, l3, 2); // mv.visitLocalVariable("e", "Ljava/lang/Exception;", null, l10, l8, 2); mv.visitMaxs(6, 3); mv.visitEnd(); } public static void generateJLCGC(ClassWriter cw, String classname) { FieldVisitor fv = cw.visitField(ACC_PUBLIC + ACC_STATIC, "__sljlcgc", "Ljava/lang/reflect/Method;", null, null); fv.visitEnd(); MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_VARARGS, "__sljlcgc", "(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/reflect/Constructor;", null, new String[] { "java/lang/NoSuchMethodException" }); mv.visitCode(); Label l0 = new Label(); Label l1 = new Label(); Label l2 = new Label(); mv.visitTryCatchBlock(l0, l1, l2, "java/lang/reflect/InvocationTargetException"); Label l3 = new Label(); mv.visitTryCatchBlock(l0, l1, l3, "java/lang/Exception"); Label l4 = new Label(); mv.visitLabel(l4); mv.visitFieldInsn(GETSTATIC, classname, "__sljlcgc", "Ljava/lang/reflect/Method;"); mv.visitJumpInsn(IFNONNULL, l0); Label l5 = new Label(); mv.visitLabel(l5); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getConstructor", "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;"); mv.visitInsn(ARETURN); mv.visitLabel(l0); mv.visitFieldInsn(GETSTATIC, classname, "__sljlcgc", "Ljava/lang/reflect/Method;"); mv.visitInsn(ACONST_NULL); mv.visitInsn(ICONST_2); mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(AASTORE); mv.visitInsn(DUP); mv.visitInsn(ICONST_1); mv.visitVarInsn(ALOAD, 1); mv.visitInsn(AASTORE); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); mv.visitTypeInsn(CHECKCAST, "java/lang/reflect/Constructor"); mv.visitLabel(l1); mv.visitInsn(ARETURN); mv.visitLabel(l2); mv.visitVarInsn(ASTORE, 2); Label l6 = new Label(); mv.visitLabel(l6); mv.visitVarInsn(ALOAD, 2); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "printStackTrace", "()V"); Label l7 = new Label(); mv.visitLabel(l7); mv.visitVarInsn(ALOAD, 2); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "getCause", "()Ljava/lang/Throwable;"); mv.visitTypeInsn(INSTANCEOF, "java/lang/NoSuchMethodException"); Label l8 = new Label(); mv.visitJumpInsn(IFEQ, l8); Label l9 = new Label(); mv.visitLabel(l9); mv.visitVarInsn(ALOAD, 2); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "getCause", "()Ljava/lang/Throwable;"); mv.visitTypeInsn(CHECKCAST, "java/lang/NoSuchMethodException"); mv.visitInsn(ATHROW); mv.visitLabel(l3); mv.visitVarInsn(ASTORE, 2); Label l10 = new Label(); mv.visitLabel(l10); // mv.visitVarInsn(ALOAD, 2); // mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Exception", "printStackTrace", "()V"); mv.visitLabel(l8); mv.visitInsn(ACONST_NULL); mv.visitInsn(ARETURN); Label l11 = new Label(); mv.visitLabel(l11); // mv.visitLocalVariable("clazz", "Ljava/lang/Class;", "Ljava/lang/Class<*>;", l4, l11, 0); // mv.visitLocalVariable("parameterTypes", "[Ljava/lang/Class;", null, l4, l11, 1); // mv.visitLocalVariable("ite", "Ljava/lang/reflect/InvocationTargetException;", null, l6, l3, 2); // mv.visitLocalVariable("e", "Ljava/lang/Exception;", null, l10, l8, 2); mv.visitMaxs(6, 3); mv.visitEnd(); } public static void generateJLCMethod(ClassWriter cw, String classname, String membername, String methodname) { FieldVisitor fv = cw.visitField(ACC_PUBLIC + ACC_STATIC, membername, "Ljava/lang/reflect/Method;", null, null); fv.visitEnd(); MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_VARARGS, membername, "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", null, new String[] { "java/lang/NoSuchMethodException" }); mv.visitCode(); Label l0 = new Label(); Label l1 = new Label(); Label l2 = new Label(); mv.visitTryCatchBlock(l0, l1, l2, "java/lang/reflect/InvocationTargetException"); Label l3 = new Label(); mv.visitTryCatchBlock(l0, l1, l3, "java/lang/Exception"); Label l4 = new Label(); mv.visitLabel(l4); mv.visitFieldInsn(GETSTATIC, classname, membername, "Ljava/lang/reflect/Method;"); mv.visitJumpInsn(IFNONNULL, l0); Label l5 = new Label(); mv.visitLabel(l5); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 2); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", methodname, "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"); mv.visitInsn(ARETURN); mv.visitLabel(l0); mv.visitFieldInsn(GETSTATIC, classname, membername, "Ljava/lang/reflect/Method;"); mv.visitInsn(ACONST_NULL); mv.visitInsn(ICONST_3); mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(AASTORE); mv.visitInsn(DUP); mv.visitInsn(ICONST_1); mv.visitVarInsn(ALOAD, 1); mv.visitInsn(AASTORE); mv.visitInsn(DUP); mv.visitInsn(ICONST_2); mv.visitVarInsn(ALOAD, 2); mv.visitInsn(AASTORE); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); mv.visitTypeInsn(CHECKCAST, "java/lang/reflect/Method"); mv.visitLabel(l1); mv.visitInsn(ARETURN); mv.visitLabel(l2); mv.visitVarInsn(ASTORE, 3); Label l6 = new Label(); mv.visitLabel(l6); // Don't print the exception if just unwrapping it // mv.visitVarInsn(ALOAD, 3); // mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "printStackTrace", "()V"); Label l7 = new Label(); mv.visitLabel(l7); mv.visitVarInsn(ALOAD, 3); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "getCause", "()Ljava/lang/Throwable;"); mv.visitTypeInsn(INSTANCEOF, "java/lang/NoSuchMethodException"); Label l8 = new Label(); mv.visitJumpInsn(IFEQ, l8); Label l9 = new Label(); mv.visitLabel(l9); mv.visitVarInsn(ALOAD, 3); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "getCause", "()Ljava/lang/Throwable;"); mv.visitTypeInsn(CHECKCAST, "java/lang/NoSuchMethodException"); mv.visitInsn(ATHROW); mv.visitLabel(l3); mv.visitVarInsn(ASTORE, 3); Label l10 = new Label(); mv.visitLabel(l10); mv.visitVarInsn(ALOAD, 3); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Exception", "printStackTrace", "()V"); mv.visitLabel(l8); mv.visitInsn(ACONST_NULL); mv.visitInsn(ARETURN); Label l11 = new Label(); mv.visitLabel(l11); // mv.visitLocalVariable("clazz", "Ljava/lang/Class;", "Ljava/lang/Class<*>;", l4, l11, 0); // mv.visitLocalVariable("methodname", "Ljava/lang/String;", null, l4, l11, 1); // mv.visitLocalVariable("parameterTypes", "[Ljava/lang/Class;", null, l4, l11, 2); // mv.visitLocalVariable("ite", "Ljava/lang/reflect/InvocationTargetException;", null, l6, l3, 3); // mv.visitLocalVariable("e", "Ljava/lang/Exception;", null, l10, l8, 3); mv.visitMaxs(6, 4); mv.visitEnd(); } public static void generateJLCMethod(ClassWriter cw, String classname, String operation) { if (operation.equals("getDeclaredMethod")) { generateJLCMethod(cw, classname, "__sljlcgdm", "getDeclaredMethod"); } else if (operation.equals("getMethod")) { generateJLCMethod(cw, classname, "__sljlcgm", "getMethod"); } else { throw new IllegalStateException("nyi:" + operation); } } public static void generateJLC(ClassWriter cw, String classname, String operation) { if (operation.equals("getDeclaredField")) { generateJLCGDF(cw, classname, "__sljlcgdf", "getDeclaredField"); } else if (operation.equals("getField")) { generateJLCGDF(cw, classname, "__sljlcgf", "getField"); } else { throw new IllegalStateException("nyi:" + operation); } } public static void generateJLCGDF(ClassWriter cw, String classname, String fieldname, String methodname) { FieldVisitor fv = cw.visitField(ACC_PUBLIC_STATIC, fieldname, "Ljava/lang/reflect/Method;", null, null); fv.visitEnd(); MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC, fieldname, "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/reflect/Field;", null, new String[] { "java/lang/NoSuchFieldException" }); mv.visitCode(); Label l0 = new Label(); Label l1 = new Label(); Label l2 = new Label(); mv.visitTryCatchBlock(l0, l1, l2, "java/lang/reflect/InvocationTargetException"); Label l3 = new Label(); mv.visitTryCatchBlock(l0, l1, l3, "java/lang/Exception"); Label l4 = new Label(); mv.visitLabel(l4); mv.visitFieldInsn(GETSTATIC, classname, fieldname, "Ljava/lang/reflect/Method;"); mv.visitJumpInsn(IFNONNULL, l0); Label l5 = new Label(); mv.visitLabel(l5); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", methodname, "(Ljava/lang/String;)Ljava/lang/reflect/Field;"); mv.visitInsn(ARETURN); mv.visitLabel(l0); mv.visitFieldInsn(GETSTATIC, classname, fieldname, "Ljava/lang/reflect/Method;"); mv.visitInsn(ACONST_NULL); mv.visitInsn(ICONST_2); mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(AASTORE); mv.visitInsn(DUP); mv.visitInsn(ICONST_1); mv.visitVarInsn(ALOAD, 1); mv.visitInsn(AASTORE); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); mv.visitTypeInsn(CHECKCAST, "java/lang/reflect/Field"); mv.visitLabel(l1); mv.visitInsn(ARETURN); mv.visitLabel(l2); mv.visitVarInsn(ASTORE, 2); Label l6 = new Label(); mv.visitLabel(l6); mv.visitVarInsn(ALOAD, 2); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "getCause", "()Ljava/lang/Throwable;"); mv.visitTypeInsn(INSTANCEOF, "java/lang/NoSuchFieldException"); Label l7 = new Label(); mv.visitJumpInsn(IFEQ, l7); Label l8 = new Label(); mv.visitLabel(l8); mv.visitVarInsn(ALOAD, 2); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "getCause", "()Ljava/lang/Throwable;"); mv.visitTypeInsn(CHECKCAST, "java/lang/NoSuchFieldException"); mv.visitInsn(ATHROW); mv.visitLabel(l3); mv.visitVarInsn(ASTORE, 2); mv.visitLabel(l7); mv.visitInsn(ACONST_NULL); mv.visitInsn(ARETURN); Label l9 = new Label(); mv.visitLabel(l9); // mv.visitLocalVariable("clazz", "Ljava/lang/Class;", "Ljava/lang/Class<*>;", l4, l9, 0); // mv.visitLocalVariable("fieldname", "Ljava/lang/String;", null, l4, l9, 1); // mv.visitLocalVariable("ite", "Ljava/lang/reflect/InvocationTargetException;", null, l6, l3, 2); mv.visitMaxs(6, 3); mv.visitEnd(); } public static void generateJLCGetXXXMethods(ClassWriter cw, String classname, String variant) { if (variant.equals("getDeclaredMethods")) { generateJLCGDMS(cw, classname, "__sljlcgdms", "getDeclaredMethods"); } else if (variant.equals("getMethods")) { generateJLCGDMS(cw, classname, "__sljlcgms", "getMethods"); } else { throw new IllegalStateException(variant); } } // TODO remove extraneous visits to things like lvar names public static void generateJLCGDMS(ClassWriter cw, String classname, String field, String methodname) { FieldVisitor fv = cw.visitField(ACC_PUBLIC + ACC_STATIC, field, "Ljava/lang/reflect/Method;", null, null); fv.visitEnd(); MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC, field, "(Ljava/lang/Class;)[Ljava/lang/reflect/Method;", null, null); mv.visitCode(); Label l0 = new Label(); Label l1 = new Label(); Label l2 = new Label(); mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Exception"); Label l3 = new Label(); mv.visitLabel(l3); mv.visitFieldInsn(GETSTATIC, classname, field, "Ljava/lang/reflect/Method;"); mv.visitJumpInsn(IFNONNULL, l0); Label l4 = new Label(); mv.visitLabel(l4); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", methodname, "()[Ljava/lang/reflect/Method;"); mv.visitInsn(ARETURN); mv.visitLabel(l0); mv.visitFieldInsn(GETSTATIC, classname, field, "Ljava/lang/reflect/Method;"); mv.visitInsn(ACONST_NULL); mv.visitInsn(ICONST_1); mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(AASTORE); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); mv.visitTypeInsn(CHECKCAST, "[Ljava/lang/reflect/Method;"); mv.visitLabel(l1); mv.visitInsn(ARETURN); mv.visitLabel(l2); mv.visitVarInsn(ASTORE, 1); Label l5 = new Label(); mv.visitLabel(l5); mv.visitInsn(ACONST_NULL); mv.visitInsn(ARETURN); Label l6 = new Label(); mv.visitLabel(l6); // mv.visitLocalVariable("clazz", "Ljava/lang/Class;", "Ljava/lang/Class<*>;", l3, l6, 0); // mv.visitLocalVariable("e", "Ljava/lang/Exception;", null, l5, l6, 1); mv.visitMaxs(6, 2); mv.visitEnd(); } public static void generateJLCGDFS(ClassWriter cw, String classname) { FieldVisitor fv = cw.visitField(ACC_PUBLIC_STATIC, "__sljlcgdfs", "Ljava/lang/reflect/Method;", null, null); fv.visitEnd(); MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC, "__sljlcgdfs", "(Ljava/lang/Class;)[Ljava/lang/reflect/Field;", null, null); mv.visitCode(); Label l0 = new Label(); Label l1 = new Label(); Label l2 = new Label(); mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Exception"); Label l3 = new Label(); mv.visitLabel(l3); mv.visitFieldInsn(GETSTATIC, classname, "__sljlcgdfs", "Ljava/lang/reflect/Method;"); mv.visitJumpInsn(IFNONNULL, l0); Label l4 = new Label(); mv.visitLabel(l4); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getDeclaredFields", "()[Ljava/lang/reflect/Field;"); mv.visitInsn(ARETURN); mv.visitLabel(l0); mv.visitFieldInsn(GETSTATIC, classname, "__sljlcgdfs", "Ljava/lang/reflect/Method;"); mv.visitInsn(ACONST_NULL); mv.visitInsn(ICONST_1); mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(AASTORE); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); mv.visitTypeInsn(CHECKCAST, "[Ljava/lang/reflect/Field;"); mv.visitLabel(l1); mv.visitInsn(ARETURN); mv.visitLabel(l2); mv.visitVarInsn(ASTORE, 1); Label l5 = new Label(); mv.visitLabel(l5); mv.visitInsn(ACONST_NULL); mv.visitInsn(ARETURN); Label l6 = new Label(); mv.visitLabel(l6); // mv.visitLocalVariable("clazz", "Ljava/lang/Class;", "Ljava/lang/Class<*>;", l3, l6, 0); // mv.visitLocalVariable("e", "Ljava/lang/Exception;", null, l5, l6, 1); mv.visitMaxs(6, 2); mv.visitEnd(); } // Can be useful for debugging, insert printlns // private static void insertPrintln(MethodVisitor mv, String message) { // mv.visitFieldInsn(GETSTATIC, "java/lang/System", "err", "Ljava/io/PrintStream;"); // mv.visitLdcInsn(message); // mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); // } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy