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