1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.bcel;
18
19 import java.lang.reflect.InvocationTargetException;
20 import java.util.LinkedList;
21 import java.util.List;
22
23 import org.apache.bcel.classfile.JavaClass;
24 import org.apache.bcel.classfile.Method;
25 import org.apache.bcel.generic.ACONST_NULL;
26 import org.apache.bcel.generic.ALOAD;
27 import org.apache.bcel.generic.ConstantPoolGen;
28 import org.apache.bcel.generic.GETSTATIC;
29 import org.apache.bcel.generic.INVOKEVIRTUAL;
30 import org.apache.bcel.generic.Instruction;
31 import org.apache.bcel.generic.InstructionList;
32 import org.apache.bcel.generic.LocalVariableGen;
33 import org.apache.bcel.generic.MethodGen;
34 import org.apache.bcel.generic.Type;
35 import org.junit.jupiter.api.Test;
36
37 public class LocalVariableTypeTableTestCase extends AbstractTestCase {
38
39 public class TestClassLoader extends ClassLoader {
40
41 public TestClassLoader(final ClassLoader parent) {
42 super(parent);
43 }
44
45 public Class<?> findClass(final String name, final byte[] bytes) {
46 return defineClass(name, bytes, 0, bytes.length);
47 }
48 }
49
50 public InstructionList createPrintln(final ConstantPoolGen cp, final Instruction instruction) {
51 final InstructionList il = new InstructionList();
52
53 final int out = cp.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;");
54 final int println = cp.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V");
55 il.append(new GETSTATIC(out));
56 il.append(instruction);
57 il.append(new INVOKEVIRTUAL(println));
58
59 return il;
60 }
61
62 public int findFirstStringLocalVariableOffset(final Method method) {
63 final Type[] argumentTypes = method.getArgumentTypes();
64 int offset = -1;
65
66 for (int i = 0, count = argumentTypes.length; i < count; i++) {
67 if (Type.STRING.getSignature().equals(argumentTypes[i].getSignature())) {
68 if (method.isStatic()) {
69 offset = i;
70 } else {
71 offset = i + 1;
72 }
73
74 break;
75 }
76 }
77
78 return offset;
79 }
80
81 private byte[] getBytesFromClass(final String className) throws ClassNotFoundException {
82 final JavaClass clazz = getTestJavaClass(className);
83 final ConstantPoolGen cp = new ConstantPoolGen(clazz.getConstantPool());
84
85 final Method[] methods = clazz.getMethods();
86
87 for (int i = 0; i < methods.length; i++) {
88 final Method method = methods[i];
89 if (!method.isNative() && !method.isAbstract()) {
90 methods[i] = injection(clazz, method, cp, findFirstStringLocalVariableOffset(method));
91 }
92 }
93
94 clazz.setConstantPool(cp.getFinalConstantPool());
95
96 return clazz.getBytes();
97 }
98
99 public Method injection(final JavaClass clazz, Method method, final ConstantPoolGen cp, final int firstStringOffset) {
100 final MethodGen methodGen = new MethodGen(method, clazz.getClassName(), cp);
101
102 final InstructionList instructionList = methodGen.getInstructionList();
103 instructionList.insert(instructionList.getStart(), makeWillBeAddedInstructionList(methodGen, firstStringOffset));
104
105 methodGen.setMaxStack();
106 methodGen.setMaxLocals();
107
108 method = methodGen.getMethod();
109 instructionList.dispose();
110
111 return method;
112 }
113
114 public InstructionList makeWillBeAddedInstructionList(final MethodGen methodGen, final int firstStringOffset) {
115 if (firstStringOffset == -1) {
116 return new InstructionList();
117 }
118
119 final LocalVariableGen localVariableGen = methodGen.getLocalVariables()[firstStringOffset];
120 Instruction instruction;
121
122 if (localVariableGen != null) {
123 instruction = new ALOAD(localVariableGen.getIndex());
124 } else {
125 instruction = new ACONST_NULL();
126 }
127
128 return createPrintln(methodGen.getConstantPool(), instruction);
129 }
130
131 @Test
132 public void testWithGenericArguement() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
133 final String targetClass = PACKAGE_BASE_NAME + ".data.SimpleClassHasMethodIncludeGenericArgument";
134 final TestClassLoader loader = new TestClassLoader(getClass().getClassLoader());
135 final Class<?> cls = loader.findClass(targetClass, getBytesFromClass(targetClass));
136
137 java.lang.reflect.Method method = cls.getDeclaredMethod("a", String.class, List.class);
138 method.invoke(null, "a1", new LinkedList<>());
139 method = cls.getDeclaredMethod("b", String.class, List.class);
140 method.invoke(null, "b1", new LinkedList<>());
141 method = cls.getDeclaredMethod("c", String.class, String.class);
142 method.invoke(null, "c1", "c2");
143 method = cls.getDeclaredMethod("d", List.class, String.class);
144 method.invoke(null, new LinkedList<>(), "d2");
145 }
146 }