KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > core > LocalVariableTableParameterNameDiscoverer


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.core;
18
19 import java.io.IOException JavaDoc;
20 import java.lang.reflect.Constructor JavaDoc;
21 import java.lang.reflect.Method JavaDoc;
22 import java.util.ArrayList JavaDoc;
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 /**
36  * Implementation of ParameterNameDiscover that uses the LocalVariableTable
37  * information in the method attributes to discover parameter names. Returns
38  * <code>null</code> if the class file was compiled without debug information.
39  *
40  * <p>Uses ObjectWeb's ASM library for analyzing class files.
41  *
42  * @author Adrian Colyer
43  * @author Juergen Hoeller
44  * @since 2.0
45  */

46 public class LocalVariableTableParameterNameDiscoverer implements ParameterNameDiscoverer {
47
48     private static Log logger = LogFactory.getLog(LocalVariableTableParameterNameDiscoverer.class);
49
50
51     public String JavaDoc[] getParameterNames(Method JavaDoc method) {
52         ParameterNameDiscoveringVisitor visitor = null;
53         try {
54             visitor = visitMethod(method);
55             if (visitor.foundTargetMember()) {
56                 return visitor.getParameterNames();
57             }
58         }
59         catch (IOException JavaDoc ex) {
60             // We couldn't load the class file, which is not fatal as it
61
// simply means this method of discovering parameter names won't work.
62
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 JavaDoc[] getParameterNames(Constructor JavaDoc ctor) {
73         ParameterNameDiscoveringVisitor visitor = null;
74         try {
75             visitor = visitConstructor(ctor);
76             if (visitor.foundTargetMember()) {
77                 return visitor.getParameterNames();
78             }
79         }
80         catch (IOException JavaDoc ex) {
81             // We couldn't load the class file, which is not fatal as it
82
// simply means this method of discovering parameter names won't work.
83
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     /**
94      * Visit the given method and discover its parameter names.
95      */

96     private ParameterNameDiscoveringVisitor visitMethod(Method JavaDoc method) throws IOException JavaDoc {
97         ClassReader classReader = createClassReader(method.getDeclaringClass());
98         FindMethodParameterNamesClassVisitor classVisitor = new FindMethodParameterNamesClassVisitor(method);
99         classReader.accept(classVisitor, false);
100         return classVisitor;
101     }
102
103     /**
104      * Visit the given constructor and discover its parameter names.
105      */

106     private ParameterNameDiscoveringVisitor visitConstructor(Constructor JavaDoc ctor) throws IOException JavaDoc {
107         ClassReader classReader = createClassReader(ctor.getDeclaringClass());
108         FindConstructorParameterNamesClassVisitor classVisitor = new FindConstructorParameterNamesClassVisitor(ctor);
109         classReader.accept(classVisitor, false);
110         return classVisitor;
111     }
112
113     /**
114      * Create a ClassReader for the given class.
115      */

116     private ClassReader createClassReader(Class JavaDoc clazz) throws IOException JavaDoc {
117         return new ClassReader(clazz.getResourceAsStream(ClassUtils.getClassFileName(clazz)));
118     }
119
120
121     /**
122      * Helper class that looks for a given member name and descriptor, and then
123      * attempts to find the parameter names for that member.
124      */

125     private static abstract class ParameterNameDiscoveringVisitor extends EmptyVisitor {
126
127         private String JavaDoc methodNameToMatch;
128
129         private String JavaDoc descriptorToMatch;
130
131         private int numParamsExpected;
132
133         private boolean foundTargetMember = false;
134
135         private String JavaDoc[] parameterNames;
136         
137         public ParameterNameDiscoveringVisitor(String JavaDoc name,int numParams) {
138             this.methodNameToMatch = name;
139             this.numParamsExpected = numParams;
140         }
141         
142         public void setDescriptorToMatch(String JavaDoc descriptor) {
143             this.descriptorToMatch = descriptor;
144         }
145
146         public MethodVisitor visitMethod(int access, String JavaDoc name, String JavaDoc desc, String JavaDoc signature, String JavaDoc[] 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                 // not interested in this method...
154
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 JavaDoc[] getParameterNames() {
167             if (!foundTargetMember()) {
168                 throw new IllegalStateException JavaDoc("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 JavaDoc[] names) {
175             this.parameterNames = names;
176         }
177     }
178
179
180     private static class FindMethodParameterNamesClassVisitor extends ParameterNameDiscoveringVisitor {
181         
182         public FindMethodParameterNamesClassVisitor(Method JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc(this.numParameters);
218             this.memberVisitor = memberVisitor;
219         }
220         
221         public void visitLocalVariable(String JavaDoc name, String JavaDoc description, String JavaDoc 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                 /*
234                  * visitLocalVariable will never be called for static no args methods
235                  * which doesn't use any local variables.
236                  * This means that hasLVTInfo could be false for that kind of methods
237                  * even if the class has local variable info.
238                  */

239                 String JavaDoc[] names = new String JavaDoc[this.parameterNames.size()];
240                 names = (String JavaDoc[]) this.parameterNames.toArray(names);
241                 this.memberVisitor.setParameterNames(names);
242             }
243         }
244     }
245
246 }
247
Popular Tags