001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019:
020: package org.apache.axis2.description.java2wsdl.bytecode;
021:
022: import java.io.IOException;
023: import java.lang.reflect.Constructor;
024: import java.lang.reflect.Member;
025: import java.lang.reflect.Method;
026: import java.lang.reflect.Modifier;
027: import java.util.HashMap;
028: import java.util.Map;
029:
030: /**
031: * This is the class file reader for obtaining the parameter names
032: * for declared methods in a class. The class must have debugging
033: * attributes for us to obtain this information. <p>
034: * <p/>
035: * This does not work for inherited methods. To obtain parameter
036: * names for inherited methods, you must use a paramReader for the
037: * class that originally declared the method. <p>
038: * <p/>
039: * don't get tricky, it's the bare minimum. Instances of this class
040: * are not threadsafe -- don't share them. <p>
041: */
042: public class ParamReader extends ClassReader {
043: private String methodName;
044: private Map methods = new HashMap();
045: private Class[] paramTypes;
046:
047: /**
048: * Processes a class file, given it's class. We'll use the defining
049: * classloader to locate the bytecode.
050: *
051: * @param c
052: * @throws java.io.IOException
053: */
054: public ParamReader(Class c) throws IOException {
055: this (getBytes(c));
056: }
057:
058: /**
059: * Processes the given class bytes directly.
060: *
061: * @param b
062: * @throws IOException
063: */
064: public ParamReader(byte[] b) throws IOException {
065: super (b, findAttributeReaders(ParamReader.class));
066:
067: // check the magic number
068: if (readInt() != 0xCAFEBABE) {
069: // not a class file!
070: throw new IOException(
071: "Error looking for paramter names in bytecode: input does not appear to be a valid class file");
072: }
073:
074: readShort(); // minor version
075: readShort(); // major version
076:
077: readCpool(); // slurp in the constant pool
078:
079: readShort(); // access flags
080: readShort(); // this class name
081: readShort(); // super class name
082:
083: int count = readShort(); // ifaces count
084: for (int i = 0; i < count; i++) {
085: readShort(); // interface index
086: }
087:
088: count = readShort(); // fields count
089: for (int i = 0; i < count; i++) {
090: readShort(); // access flags
091: readShort(); // name index
092: readShort(); // descriptor index
093: skipAttributes(); // field attributes
094: }
095:
096: count = readShort(); // methods count
097: for (int i = 0; i < count; i++) {
098: readShort(); // access flags
099: int m = readShort(); // name index
100: String name = resolveUtf8(m);
101: int d = readShort(); // descriptor index
102: this .methodName = name + resolveUtf8(d);
103: readAttributes(); // method attributes
104: }
105:
106: }
107:
108: public void readCode() throws IOException {
109: readShort(); // max stack
110: int maxLocals = readShort(); // max locals
111:
112: MethodInfo info = new MethodInfo(maxLocals);
113: if (methods != null && methodName != null) {
114: methods.put(methodName, info);
115: }
116:
117: skipFully(readInt()); // code
118: skipFully(8 * readShort()); // exception table
119: // read the code attributes (recursive). This is where
120: // we will find the LocalVariableTable attribute.
121: readAttributes();
122: }
123:
124: /**
125: * Returns the names of the declared parameters for the given constructor.
126: * If we cannot determine the names, return null. The returned array will
127: * have one name per parameter. The length of the array will be the same
128: * as the length of the Class[] array returned by Constructor.getParameterTypes().
129: *
130: * @param ctor
131: * @return Returns String[] array of names, one per parameter, or null
132: */
133: public String[] getParameterNames(Constructor ctor) {
134: paramTypes = ctor.getParameterTypes();
135: return getParameterNames(ctor, paramTypes);
136: }
137:
138: /**
139: * Returns the names of the declared parameters for the given method.
140: * If we cannot determine the names, return null. The returned array will
141: * have one name per parameter. The length of the array will be the same
142: * as the length of the Class[] array returned by Method.getParameterTypes().
143: *
144: * @param method
145: * @return Returns String[] array of names, one per parameter, or null
146: */
147: public String[] getParameterNames(Method method) {
148: paramTypes = method.getParameterTypes();
149: return getParameterNames(method, paramTypes);
150: }
151:
152: protected String[] getParameterNames(Member member,
153: Class[] paramTypes) {
154: // look up the names for this method
155: MethodInfo info = (MethodInfo) methods.get(getSignature(member,
156: paramTypes));
157:
158: // we know all the local variable names, but we only need to return
159: // the names of the parameters.
160:
161: if (info != null) {
162: String[] paramNames = new String[paramTypes.length];
163: int j = Modifier.isStatic(member.getModifiers()) ? 0 : 1;
164:
165: boolean found = false; // did we find any non-null names
166: for (int i = 0; i < paramNames.length; i++) {
167: if (info.names[j] != null) {
168: found = true;
169: paramNames[i] = info.names[j];
170: }
171: j++;
172: if (paramTypes[i] == double.class
173: || paramTypes[i] == long.class) {
174: // skip a slot for 64bit params
175: j++;
176: }
177: }
178:
179: if (found) {
180: return paramNames;
181: } else {
182: return null;
183: }
184: } else {
185: return null;
186: }
187: }
188:
189: private static class MethodInfo {
190: String[] names;
191: int maxLocals;
192:
193: public MethodInfo(int maxLocals) {
194: this .maxLocals = maxLocals;
195: names = new String[maxLocals];
196: }
197: }
198:
199: private MethodInfo getMethodInfo() {
200: MethodInfo info = null;
201: if (methods != null && methodName != null) {
202: info = (MethodInfo) methods.get(methodName);
203: }
204: return info;
205: }
206:
207: /**
208: * This is invoked when a LocalVariableTable attribute is encountered.
209: *
210: * @throws IOException
211: */
212: public void readLocalVariableTable() throws IOException {
213: int len = readShort(); // table length
214: MethodInfo info = getMethodInfo();
215: for (int j = 0; j < len; j++) {
216: readShort(); // start pc
217: readShort(); // length
218: int nameIndex = readShort(); // name_index
219: readShort(); // descriptor_index
220: int index = readShort(); // local index
221: if (info != null) {
222: info.names[index] = resolveUtf8(nameIndex);
223: }
224: }
225: }
226: }
|