1 16 17 package org.springframework.core; 18 19 import java.io.IOException ; 20 import java.lang.reflect.Constructor ; 21 import java.lang.reflect.Method ; 22 import java.util.ArrayList ; 23 24 import org.apache.commons.logging.Log; 25 import org.apache.commons.logging.LogFactory; 26 import org.objectweb.asm.ClassReader; 27 import org.objectweb.asm.Label; 28 import org.objectweb.asm.MethodVisitor; 29 import org.objectweb.asm.Opcodes; 30 import org.objectweb.asm.Type; 31 import org.objectweb.asm.commons.EmptyVisitor; 32 33 import org.springframework.util.ClassUtils; 34 35 46 public class LocalVariableTableParameterNameDiscoverer implements ParameterNameDiscoverer { 47 48 private static Log logger = LogFactory.getLog(LocalVariableTableParameterNameDiscoverer.class); 49 50 51 public String [] getParameterNames(Method method) { 52 ParameterNameDiscoveringVisitor visitor = null; 53 try { 54 visitor = visitMethod(method); 55 if (visitor.foundTargetMember()) { 56 return visitor.getParameterNames(); 57 } 58 } 59 catch (IOException ex) { 60 if (logger.isDebugEnabled()) { 63 logger.debug("IOException whilst attempting to read '.class' file for class [" + 64 method.getDeclaringClass().getName() + 65 "] - unable to determine parameter names for method: " + method, 66 ex); 67 } 68 } 69 return null; 70 } 71 72 public String [] getParameterNames(Constructor ctor) { 73 ParameterNameDiscoveringVisitor visitor = null; 74 try { 75 visitor = visitConstructor(ctor); 76 if (visitor.foundTargetMember()) { 77 return visitor.getParameterNames(); 78 } 79 } 80 catch (IOException ex) { 81 if (logger.isDebugEnabled()) { 84 logger.debug("IOException whilst attempting to read '.class' file for class [" + 85 ctor.getDeclaringClass().getName() + 86 "] - unable to determine parameter names for constructor: " + ctor, 87 ex); 88 } 89 } 90 return null; 91 } 92 93 96 private ParameterNameDiscoveringVisitor visitMethod(Method method) throws IOException { 97 ClassReader classReader = createClassReader(method.getDeclaringClass()); 98 FindMethodParameterNamesClassVisitor classVisitor = new FindMethodParameterNamesClassVisitor(method); 99 classReader.accept(classVisitor, false); 100 return classVisitor; 101 } 102 103 106 private ParameterNameDiscoveringVisitor visitConstructor(Constructor ctor) throws IOException { 107 ClassReader classReader = createClassReader(ctor.getDeclaringClass()); 108 FindConstructorParameterNamesClassVisitor classVisitor = new FindConstructorParameterNamesClassVisitor(ctor); 109 classReader.accept(classVisitor, false); 110 return classVisitor; 111 } 112 113 116 private ClassReader createClassReader(Class clazz) throws IOException { 117 return new ClassReader(clazz.getResourceAsStream(ClassUtils.getClassFileName(clazz))); 118 } 119 120 121 125 private static abstract class ParameterNameDiscoveringVisitor extends EmptyVisitor { 126 127 private String methodNameToMatch; 128 129 private String descriptorToMatch; 130 131 private int numParamsExpected; 132 133 private boolean foundTargetMember = false; 134 135 private String [] parameterNames; 136 137 public ParameterNameDiscoveringVisitor(String name,int numParams) { 138 this.methodNameToMatch = name; 139 this.numParamsExpected = numParams; 140 } 141 142 public void setDescriptorToMatch(String descriptor) { 143 this.descriptorToMatch = descriptor; 144 } 145 146 public MethodVisitor visitMethod(int access, String name, String desc, String signature, String [] exceptions) { 147 if (name.equals(this.methodNameToMatch) && 148 desc.equals(this.descriptorToMatch)) { 149 this.foundTargetMember = true; 150 return new LocalVariableTableVisitor(isStatic(access), this,this.numParamsExpected); 151 } 152 else { 153 return null; 155 } 156 } 157 158 private boolean isStatic(int access) { 159 return ((access & Opcodes.ACC_STATIC) > 0); 160 } 161 162 public boolean foundTargetMember() { 163 return this.foundTargetMember; 164 } 165 166 public String [] getParameterNames() { 167 if (!foundTargetMember()) { 168 throw new IllegalStateException ("Can't ask for parameter names when target member has not been found"); 169 } 170 171 return this.parameterNames; 172 } 173 174 public void setParameterNames(String [] names) { 175 this.parameterNames = names; 176 } 177 } 178 179 180 private static class FindMethodParameterNamesClassVisitor extends ParameterNameDiscoveringVisitor { 181 182 public FindMethodParameterNamesClassVisitor(Method method) { 183 super(method.getName(),method.getParameterTypes().length); 184 setDescriptorToMatch(Type.getMethodDescriptor(method)); 185 } 186 } 187 188 189 private static class FindConstructorParameterNamesClassVisitor extends ParameterNameDiscoveringVisitor { 190 191 public FindConstructorParameterNamesClassVisitor(Constructor cons) { 192 super("<init>",cons.getParameterTypes().length); 193 Type[] pTypes = new Type[cons.getParameterTypes().length]; 194 for (int i = 0; i < pTypes.length; i++) { 195 pTypes[i] = Type.getType(cons.getParameterTypes()[i]); 196 } 197 setDescriptorToMatch(Type.getMethodDescriptor(Type.VOID_TYPE,pTypes)); 198 } 199 } 200 201 202 private static class LocalVariableTableVisitor extends EmptyVisitor { 203 204 private boolean isStatic; 205 206 private ParameterNameDiscoveringVisitor memberVisitor; 207 208 private int numParameters; 209 210 private ArrayList parameterNames; 211 212 private boolean hasLVTInfo = false; 213 214 public LocalVariableTableVisitor(boolean isStatic, ParameterNameDiscoveringVisitor memberVisitor, int numParams) { 215 this.isStatic = isStatic; 216 this.numParameters = numParams; 217 this.parameterNames = new ArrayList (this.numParameters); 218 this.memberVisitor = memberVisitor; 219 } 220 221 public void visitLocalVariable(String name, String description, String signature, Label start, Label end, int index) { 222 this.hasLVTInfo = true; 223 if (!this.isStatic) { 224 index--; 225 } 226 if (index >= 0 && (this.parameterNames.size() < this.numParameters)) { 227 this.parameterNames.add(name); 228 } 229 } 230 231 public void visitEnd() { 232 if (this.hasLVTInfo || this.isStatic && numParameters == 0) { 233 239 String [] names = new String [this.parameterNames.size()]; 240 names = (String []) this.parameterNames.toArray(names); 241 this.memberVisitor.setParameterNames(names); 242 } 243 } 244 } 245 246 } 247 | Popular Tags |