• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 package org.apache.bcel;
19 
20 import org.apache.bcel.classfile.JavaClass;
21 import org.apache.bcel.classfile.Method;
22 import org.apache.bcel.generic.ACONST_NULL;
23 import org.apache.bcel.generic.ALOAD;
24 import org.apache.bcel.generic.ConstantPoolGen;
25 import org.apache.bcel.generic.GETSTATIC;
26 import org.apache.bcel.generic.INVOKEVIRTUAL;
27 import org.apache.bcel.generic.Instruction;
28 import org.apache.bcel.generic.InstructionList;
29 import org.apache.bcel.generic.LocalVariableGen;
30 import org.apache.bcel.generic.MethodGen;
31 import org.apache.bcel.generic.Type;
32 import org.junit.Test;
33 
34 import java.io.IOException;
35 import java.lang.reflect.InvocationTargetException;
36 import java.util.LinkedList;
37 import java.util.List;
38 
39 public class LocalVariableTypeTableTestCase extends AbstractTestCase {
40     public class TestClassLoader extends ClassLoader {
TestClassLoader(final ClassLoader parent)41         public TestClassLoader(final ClassLoader parent) {
42             super(parent);
43         }
44 
findClass(final String name, final byte[] bytes)45         public Class<?> findClass(final String name, final byte[] bytes) {
46             return defineClass(name, bytes, 0, bytes.length);
47         }
48     }
49 
50     @Test
testWithGenericArguement()51     public void testWithGenericArguement() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException {
52         final String targetClass = PACKAGE_BASE_NAME + ".data.SimpleClassHasMethodIncludeGenericArgument";
53         final TestClassLoader loader = new TestClassLoader(getClass().getClassLoader());
54         final Class cls = loader.findClass(targetClass, getBytesFromClass(targetClass));
55 
56         java.lang.reflect.Method method = cls.getDeclaredMethod("a", String.class, List.class);
57         method.invoke(null, "a1", new LinkedList<String>());
58         method = cls.getDeclaredMethod("b", String.class, List.class);
59         method.invoke(null, "b1", new LinkedList<String>());
60         method = cls.getDeclaredMethod("c", String.class, String.class);
61         method.invoke(null, "c1", "c2");
62         method = cls.getDeclaredMethod("d", List.class, String.class);
63         method.invoke(null, new LinkedList<String>(), "d2");
64     }
65 
getBytesFromClass(final String className)66     private byte[] getBytesFromClass(final String className) throws ClassNotFoundException, IOException {
67         final JavaClass clazz = getTestClass(className);
68         final ConstantPoolGen cp = new ConstantPoolGen(clazz.getConstantPool());
69 
70         final Method[] methods = clazz.getMethods();
71 
72         for (int i = 0; i < methods.length; i++) {
73             final Method method = methods[i];
74             if (!method.isNative() && !method.isAbstract()) {
75                 methods[i] = injection(clazz, method, cp, findFirstStringLocalVariableOffset(method));
76             }
77         }
78 
79         clazz.setConstantPool(cp.getFinalConstantPool());
80 
81         return clazz.getBytes();
82     }
83 
injection(final JavaClass clazz, Method method, final ConstantPoolGen cp, final int firstStringOffset)84     public Method injection(final JavaClass clazz, Method method, final ConstantPoolGen cp, final int firstStringOffset) {
85         final MethodGen methodGen = new MethodGen(method, clazz.getClassName(), cp);
86 
87         final InstructionList instructionList = methodGen.getInstructionList();
88         instructionList.insert(instructionList.getStart(), makeWillBeAddedInstructionList(methodGen, firstStringOffset));
89 
90         methodGen.setMaxStack();
91         methodGen.setMaxLocals();
92 
93         method = methodGen.getMethod();
94         instructionList.dispose();
95 
96         return method;
97     }
98 
makeWillBeAddedInstructionList(final MethodGen methodGen, final int firstStringOffset)99     public InstructionList makeWillBeAddedInstructionList(final MethodGen methodGen, final int firstStringOffset) {
100         if (firstStringOffset == -1) {
101             return new InstructionList();
102         }
103 
104         final LocalVariableGen localVariableGen = methodGen.getLocalVariables()[firstStringOffset];
105         Instruction instruction;
106 
107         if (localVariableGen != null) {
108             instruction = new ALOAD(localVariableGen.getIndex());
109         } else {
110             instruction = new ACONST_NULL();
111         }
112 
113         return createPrintln(methodGen.getConstantPool(), instruction);
114     }
115 
createPrintln(final ConstantPoolGen cp, final Instruction instruction)116     public InstructionList createPrintln(final ConstantPoolGen cp, final Instruction instruction) {
117         final InstructionList il = new InstructionList();
118 
119         final int out = cp.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;");
120         final int println = cp.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V");
121         il.append(new GETSTATIC(out));
122         il.append(instruction);
123         il.append(new INVOKEVIRTUAL(println));
124 
125         return il;
126     }
127 
findFirstStringLocalVariableOffset(final Method method)128     public int findFirstStringLocalVariableOffset(final Method method) {
129         final Type[] argumentTypes = method.getArgumentTypes();
130         int offset = -1;
131 
132         for (int i = 0, count = argumentTypes.length; i < count; i++) {
133             if (Type.STRING.getSignature().equals(argumentTypes[i].getSignature())) {
134                 if (method.isStatic()) {
135                     offset = i;
136                 } else {
137                     offset = i + 1;
138                 }
139 
140                 break;
141             }
142         }
143 
144         return offset;
145     }
146 }
147