You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@beehive.apache.org by mm...@apache.org on 2004/12/22 19:12:39 UTC
svn commit: r123132 - in incubator/beehive/trunk/wsm: drt/tests/org/apache/beehive/wsm/jsr181/processor/apt drt/tests/org/apache/beehive/wsm/jsr181/processor/reflection src/runtime/org/apache/beehive/wsm/jsr181/processor/reflection src/runtime/org/apache/beehive/wsm/jsr181/util/bytecode
Author: mmerz
Date: Wed Dec 22 10:12:38 2004
New Revision: 123132
URL: http://svn.apache.org/viewcvs?view=rev&rev=123132
Log:
Fix for BEEHIVE-120 (@WebParam.name default values). Code for reading parameter names from debug information (util/bytecode/*) was taken from Apache Axis project.
Added:
incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/util/bytecode/
incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/util/bytecode/ClassReader.java
incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/util/bytecode/ParamNameExtractor.java
incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/util/bytecode/ParamReader.java
Modified:
incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/jsr181/processor/apt/WsmAnnotationProcessorTest.java
incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/jsr181/processor/reflection/WsmAnnotationProcessorTest.java
incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/processor/reflection/WsmReflectionAnnotationProcessor.java
Modified: incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/jsr181/processor/apt/WsmAnnotationProcessorTest.java
Url: http://svn.apache.org/viewcvs/incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/jsr181/processor/apt/WsmAnnotationProcessorTest.java?view=diff&rev=123132&p1=incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/jsr181/processor/apt/WsmAnnotationProcessorTest.java&r1=123131&p2=incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/jsr181/processor/apt/WsmAnnotationProcessorTest.java&r2=123132
==============================================================================
--- incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/jsr181/processor/apt/WsmAnnotationProcessorTest.java (original)
+++ incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/jsr181/processor/apt/WsmAnnotationProcessorTest.java Wed Dec 22 10:12:38 2004
@@ -63,7 +63,6 @@
/**
* We can't derive default values for WebParam from binaries. Thus, we use
* our own default name "in<number>".
- */
@Override
public void testWebParamGoLocoFirst() throws Exception {
final int paramNo = 0;
@@ -74,4 +73,5 @@
int.class,
param.getJavaType());
}
+ */
}
Modified: incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/jsr181/processor/reflection/WsmAnnotationProcessorTest.java
Url: http://svn.apache.org/viewcvs/incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/jsr181/processor/reflection/WsmAnnotationProcessorTest.java?view=diff&rev=123132&p1=incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/jsr181/processor/reflection/WsmAnnotationProcessorTest.java&r1=123131&p2=incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/jsr181/processor/reflection/WsmAnnotationProcessorTest.java&r2=123132
==============================================================================
--- incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/jsr181/processor/reflection/WsmAnnotationProcessorTest.java (original)
+++ incubator/beehive/trunk/wsm/drt/tests/org/apache/beehive/wsm/jsr181/processor/reflection/WsmAnnotationProcessorTest.java Wed Dec 22 10:12:38 2004
@@ -42,7 +42,6 @@
/**
* We can't derive default values for WebParam from binaries. Thus, we use
* our own default name "in<number>".
- */
@Override
public void testWebParamGoLocoFirst() throws Exception {
final int paramNo = 0;
@@ -53,5 +52,6 @@
int.class,
param.getJavaType());
}
+ */
}
Modified: incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/processor/reflection/WsmReflectionAnnotationProcessor.java
Url: http://svn.apache.org/viewcvs/incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/processor/reflection/WsmReflectionAnnotationProcessor.java?view=diff&rev=123132&p1=incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/processor/reflection/WsmReflectionAnnotationProcessor.java&r1=123131&p2=incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/processor/reflection/WsmReflectionAnnotationProcessor.java&r2=123132
==============================================================================
--- incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/processor/reflection/WsmReflectionAnnotationProcessor.java (original)
+++ incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/processor/reflection/WsmReflectionAnnotationProcessor.java Wed Dec 22 10:12:38 2004
@@ -126,20 +126,34 @@
* @param method
* @return
*/
- protected Jsr181MethodMetadata getWebServiceMETHODMetadata(Method method) {
+ protected Jsr181MethodMetadata getWebServiceMETHODMetadata(Method method)
+ {
List<Jsr181ParameterMetadata> webParams =
new ArrayList<Jsr181ParameterMetadata>();
// publish all params
Annotation[][] allAnnotations = method.getParameterAnnotations();
- int offset = 0;
- for (Class paramType : method.getParameterTypes()) {
- webParams.add(getWebServicePARAMETERMetadata(paramType,
- offset,
- Arrays.asList(allAnnotations[offset])));
- offset++;
+ final Class[] parameterTypes = method.getParameterTypes();
+ if ((null != parameterTypes) && (0 < parameterTypes.length))
+ {
+ final String[] defaultNames =
+ org.apache.beehive.wsm.jsr181.util.bytecode.ParamNameExtractor.getParameterNamesFromDebugInfo(method);
+ int offset = 0;
+ for (Class paramType : parameterTypes) {
+ String defaultName = "in" + offset;
+ if ((null != defaultNames) && (offset < defaultNames.length))
+ {
+ defaultName = defaultNames[offset];
+ }
+ webParams.add(getWebServicePARAMETERMetadata(
+ paramType,
+ defaultName,
+ Arrays.asList(allAnnotations[offset])
+ ));
+ offset++;
+ }
}
-
+
// create & return webMethod
Jsr181MethodMetadata wsmm = null;
try {
@@ -157,18 +171,18 @@
/**
* @param paramType
- * @param offset
+ * @param defaultName
* @param annotations
* @return
*/
- protected Jsr181ParameterMetadata getWebServicePARAMETERMetadata(Class paramType, int offset, List<Annotation> annotations) {
+ protected Jsr181ParameterMetadata getWebServicePARAMETERMetadata(Class paramType, String defaultName, List<Annotation> annotations) {
+
// create & return webParam
Jsr181ParameterMetadata wspm = null;
try {
- wspm = new Jsr181ParameterMetadataImpl(paramType,
- "in" + offset, // by default parameter should be IN
- annotations);
- } catch (Throwable t) {
+ wspm = new Jsr181ParameterMetadataImpl(paramType, defaultName, annotations);
+ }
+ catch (Throwable t) {
t.printStackTrace(); // todo: proper error handling
wspm = null;
}
Added: incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/util/bytecode/ClassReader.java
Url: http://svn.apache.org/viewcvs/incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/util/bytecode/ClassReader.java?view=auto&rev=123132
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/util/bytecode/ClassReader.java Wed Dec 22 10:12:38 2004
@@ -0,0 +1,426 @@
+package org.apache.beehive.wsm.jsr181.util.bytecode;
+
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This is the class file reader for obtaining the parameter names
+ * for declared methods in a class. The class must have debugging
+ * attributes for us to obtain this information. <p>
+ *
+ * This does not work for inherited methods. To obtain parameter
+ * names for inherited methods, you must use a paramReader for the
+ * class that originally declared the method. <p>
+ *
+ * don't get tricky, it's the bare minimum. Instances of this class
+ * are not threadsafe -- don't share them. <p>
+ *
+ * @author Edwin Smith, Macromedia
+ */
+public class ClassReader extends ByteArrayInputStream {
+ // constants values that appear in java class files,
+ // from jvm spec 2nd ed, section 4.4, pp 103
+ private static final int CONSTANT_Class = 7;
+ private static final int CONSTANT_Fieldref = 9;
+ private static final int CONSTANT_Methodref = 10;
+ private static final int CONSTANT_InterfaceMethodref = 11;
+ private static final int CONSTANT_String = 8;
+ private static final int CONSTANT_Integer = 3;
+ private static final int CONSTANT_Float = 4;
+ private static final int CONSTANT_Long = 5;
+ private static final int CONSTANT_Double = 6;
+ private static final int CONSTANT_NameAndType = 12;
+ private static final int CONSTANT_Utf8 = 1;
+ /**
+ * the constant pool. constant pool indices in the class file
+ * directly index into this array. The value stored in this array
+ * is the position in the class file where that constant begins.
+ */
+ private int[] cpoolIndex;
+ private Object[] cpool;
+
+ private Map attrMethods;
+
+ /**
+ * load the bytecode for a given class, by using the class's defining
+ * classloader and assuming that for a class named P.C, the bytecodes are
+ * in a resource named /P/C.class.
+ * @param c the class of interest
+ * @return a byte array containing the bytecode
+ * @throws IOException
+ */
+ protected static byte[] getBytes(Class c) throws IOException {
+ InputStream fin = c.getResourceAsStream('/' + c.getName().replace('.', '/') + ".class");
+ if (fin == null) {
+ throw new IOException("cantLoadByecode for " + c.getName());
+ }
+ try {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ byte[] buf = new byte[1024];
+ int actual;
+ do {
+ actual = fin.read(buf);
+ if (actual > 0) {
+ out.write(buf, 0, actual);
+ }
+ } while (actual > 0);
+ return out.toByteArray();
+ } finally {
+ fin.close();
+ }
+ }
+
+ static String classDescriptorToName(String desc) {
+ return desc.replace('/', '.');
+ }
+
+ protected static Map findAttributeReaders(Class c) {
+ HashMap map = new HashMap();
+ Method[] methods = c.getMethods();
+
+ for (int i = 0; i < methods.length; i++) {
+ String name = methods[i].getName();
+ if (name.startsWith("read") && methods[i].getReturnType() == void.class) {
+ map.put(name.substring(4), methods[i]);
+ }
+ }
+
+ return map;
+ }
+
+
+ protected static String getSignature(Member method, Class[] paramTypes) {
+ // compute the method descriptor
+
+ StringBuffer b = new StringBuffer((method instanceof Method) ? method.getName() : "<init>");
+ b.append('(');
+
+ for (int i = 0; i < paramTypes.length; i++) {
+ addDescriptor(b, paramTypes[i]);
+ }
+
+ b.append(')');
+ if (method instanceof Method) {
+ addDescriptor(b, ((Method) method).getReturnType());
+ } else if (method instanceof Constructor) {
+ addDescriptor(b, void.class);
+ }
+
+ return b.toString();
+ }
+
+ private static void addDescriptor(StringBuffer b, Class c) {
+ if (c.isPrimitive()) {
+ if (c == void.class)
+ b.append('V');
+ else if (c == int.class)
+ b.append('I');
+ else if (c == boolean.class)
+ b.append('Z');
+ else if (c == byte.class)
+ b.append('B');
+ else if (c == short.class)
+ b.append('S');
+ else if (c == long.class)
+ b.append('J');
+ else if (c == char.class)
+ b.append('C');
+ else if (c == float.class)
+ b.append('F');
+ else if (c == double.class) b.append('D');
+ } else if (c.isArray()) {
+ b.append('[');
+ addDescriptor(b, c.getComponentType());
+ } else {
+ b.append('L').append(c.getName().replace('.', '/')).append(';');
+ }
+ }
+
+
+ /**
+ * @return the next unsigned 16 bit value
+ */
+ protected final int readShort() {
+ return (read() << 8) | read();
+ }
+
+ /**
+ * @return the next signed 32 bit value
+ */
+ protected final int readInt() {
+ return (read() << 24) | (read() << 16) | (read() << 8) | read();
+ }
+
+ /**
+ * skip n bytes in the input stream.
+ */
+ protected void skipFully(int n) throws IOException {
+ while (n > 0) {
+ int c = (int) skip(n);
+ if (c <= 0)
+ throw new EOFException("Unexpected end of file");
+ n -= c;
+ }
+ }
+
+ protected final Member resolveMethod(int index) throws IOException, ClassNotFoundException, NoSuchMethodException {
+ int oldPos = pos;
+ try {
+ Member m = (Member) cpool[index];
+ if (m == null) {
+ pos = cpoolIndex[index];
+ Class owner = resolveClass(readShort());
+ NameAndType nt = resolveNameAndType(readShort());
+ String signature = nt.name + nt.type;
+ if (nt.name.equals("<init>")) {
+ Constructor[] ctors = owner.getConstructors();
+ for (int i = 0; i < ctors.length; i++) {
+ String sig = getSignature(ctors[i], ctors[i].getParameterTypes());
+ if (sig.equals(signature)) {
+ cpool[index] = m = ctors[i];
+ return m;
+ }
+ }
+ } else {
+ Method[] methods = owner.getDeclaredMethods();
+ for (int i = 0; i < methods.length; i++) {
+ String sig = getSignature(methods[i], methods[i].getParameterTypes());
+ if (sig.equals(signature)) {
+ cpool[index] = m = methods[i];
+ return m;
+ }
+ }
+ }
+ throw new NoSuchMethodException(signature);
+ }
+ return m;
+ } finally {
+ pos = oldPos;
+ }
+
+ }
+
+ protected final Field resolveField(int i) throws IOException, ClassNotFoundException, NoSuchFieldException {
+ int oldPos = pos;
+ try {
+ Field f = (Field) cpool[i];
+ if (f == null) {
+ pos = cpoolIndex[i];
+ Class owner = resolveClass(readShort());
+ NameAndType nt = resolveNameAndType(readShort());
+ cpool[i] = f = owner.getDeclaredField(nt.name);
+ }
+ return f;
+ } finally {
+ pos = oldPos;
+ }
+ }
+
+ private static class NameAndType {
+ String name;
+ String type;
+
+ public NameAndType(String name, String type) {
+ this.name = name;
+ this.type = type;
+ }
+ }
+
+ protected final NameAndType resolveNameAndType(int i) throws IOException {
+ int oldPos = pos;
+ try {
+ NameAndType nt = (NameAndType) cpool[i];
+ if (nt == null) {
+ pos = cpoolIndex[i];
+ String name = resolveUtf8(readShort());
+ String type = resolveUtf8(readShort());
+ cpool[i] = nt = new NameAndType(name, type);
+ }
+ return nt;
+ } finally {
+ pos = oldPos;
+ }
+ }
+
+
+ protected final Class resolveClass(int i) throws IOException, ClassNotFoundException {
+ int oldPos = pos;
+ try {
+ Class c = (Class) cpool[i];
+ if (c == null) {
+ pos = cpoolIndex[i];
+ String name = resolveUtf8(readShort());
+ cpool[i] = c = Class.forName(classDescriptorToName(name));
+ }
+ return c;
+ } finally {
+ pos = oldPos;
+ }
+ }
+
+ protected final String resolveUtf8(int i) throws IOException {
+ int oldPos = pos;
+ try {
+ String s = (String) cpool[i];
+ if (s == null) {
+ pos = cpoolIndex[i];
+ int len = readShort();
+ skipFully(len);
+ cpool[i] = s = new String(buf, pos - len, len, "utf-8");
+ }
+ return s;
+ } finally {
+ pos = oldPos;
+ }
+ }
+
+ protected final void readCpool() throws IOException {
+ int count = readShort(); // cpool count
+ cpoolIndex = new int[count];
+ cpool = new Object[count];
+ for (int i = 1; i < count; i++) {
+ int c = read();
+ cpoolIndex[i] = super.pos;
+ switch (c) // constant pool tag
+ {
+ case CONSTANT_Fieldref:
+ case CONSTANT_Methodref:
+ case CONSTANT_InterfaceMethodref:
+ case CONSTANT_NameAndType:
+
+ readShort(); // class index or (12) name index
+ // fall through
+
+ case CONSTANT_Class:
+ case CONSTANT_String:
+
+ readShort(); // string index or class index
+ break;
+
+ case CONSTANT_Long:
+ case CONSTANT_Double:
+
+ readInt(); // hi-value
+
+ // see jvm spec section 4.4.5 - double and long cpool
+ // entries occupy two "slots" in the cpool table.
+ i++;
+ // fall through
+
+ case CONSTANT_Integer:
+ case CONSTANT_Float:
+
+ readInt(); // value
+ break;
+
+ case CONSTANT_Utf8:
+
+ int len = readShort();
+ skipFully(len);
+ break;
+
+ default:
+ // corrupt class file
+ throw new IllegalStateException("Unexpected Byte");
+ }
+ }
+ }
+
+ protected final void skipAttributes() throws IOException {
+ int count = readShort();
+ for (int i = 0; i < count; i++) {
+ readShort(); // name index
+ skipFully(readInt());
+ }
+ }
+
+ /**
+ * read an attributes array. the elements of a class file that
+ * can contain attributes are: fields, methods, the class itself,
+ * and some other types of attributes.
+ */
+ protected final void readAttributes() throws IOException {
+ int count = readShort();
+ for (int i = 0; i < count; i++) {
+ int nameIndex = readShort(); // name index
+ int attrLen = readInt();
+ int curPos = pos;
+
+ String attrName = resolveUtf8(nameIndex);
+
+ Method m = (Method) attrMethods.get(attrName);
+
+ if (m != null) {
+ try {
+ m.invoke(this, new Object[]{});
+ } catch (IllegalAccessException e) {
+ pos = curPos;
+ skipFully(attrLen);
+ } catch (InvocationTargetException e) {
+ try {
+ throw e.getTargetException();
+ } catch (Error ex) {
+ throw ex;
+ } catch (RuntimeException ex) {
+ throw ex;
+ } catch (IOException ex) {
+ throw ex;
+ } catch (Throwable ex) {
+ pos = curPos;
+ skipFully(attrLen);
+ }
+ }
+ } else {
+ // don't care what attribute this is
+ skipFully(attrLen);
+ }
+ }
+ }
+
+ /**
+ * read a code attribute
+ * @throws IOException
+ */
+ public void readCode() throws IOException {
+ readShort(); // max stack
+ readShort(); // max locals
+ skipFully(readInt()); // code
+ skipFully(8 * readShort()); // exception table
+
+ // read the code attributes (recursive). This is where
+ // we will find the LocalVariableTable attribute.
+ readAttributes();
+ }
+
+ protected ClassReader(byte buf[], Map attrMethods) {
+ super(buf);
+
+ this.attrMethods = attrMethods;
+ }
+}
\ No newline at end of file
Added: incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/util/bytecode/ParamNameExtractor.java
Url: http://svn.apache.org/viewcvs/incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/util/bytecode/ParamNameExtractor.java?view=auto&rev=123132
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/util/bytecode/ParamNameExtractor.java Wed Dec 22 10:12:38 2004
@@ -0,0 +1,65 @@
+package org.apache.beehive.wsm.jsr181.util.bytecode;
+
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+/**
+ * This class retieves function parameter names from bytecode built with
+ * debugging symbols. Used as a last resort when creating WSDL.
+ *
+ * @author <a href="mailto:tomj@macromedia.com">Tom Jordahl</a>
+ */
+public class ParamNameExtractor {
+
+// protected static Log log =
+// LogFactory.getLog(ParamNameExtractor.class.getName());
+
+ /**
+ * Retrieve a list of function parameter names from a method
+ * Returns null if unable to read parameter names (i.e. bytecode not
+ * built with debug).
+ */
+ public static String[] getParameterNamesFromDebugInfo(Method method) {
+ // Don't worry about it if there are no params.
+ int numParams = method.getParameterTypes().length;
+ if (numParams == 0)
+ return null;
+
+ // get declaring class
+ Class c = method.getDeclaringClass();
+
+ // Don't worry about it if the class is a Java dynamic proxy
+ if(Proxy.isProxyClass(c)) {
+ return null;
+ }
+
+ try {
+ // get a parameter reader
+ ParamReader pr = new ParamReader(c);
+ // get the paramter names
+ String[] names = pr.getParameterNames(method);
+ return names;
+ } catch (IOException e) {
+ // log it and leave
+// log.info(Messages.getMessage("error00") + ":" + e);
+ return null;
+ }
+ }
+}
Added: incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/util/bytecode/ParamReader.java
Url: http://svn.apache.org/viewcvs/incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/util/bytecode/ParamReader.java?view=auto&rev=123132
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/wsm/src/runtime/org/apache/beehive/wsm/jsr181/util/bytecode/ParamReader.java Wed Dec 22 10:12:38 2004
@@ -0,0 +1,223 @@
+package org.apache.beehive.wsm.jsr181.util.bytecode;
+
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Member;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This is the class file reader for obtaining the parameter names
+ * for declared methods in a class. The class must have debugging
+ * attributes for us to obtain this information. <p>
+ *
+ * This does not work for inherited methods. To obtain parameter
+ * names for inherited methods, you must use a paramReader for the
+ * class that originally declared the method. <p>
+ *
+ * don't get tricky, it's the bare minimum. Instances of this class
+ * are not threadsafe -- don't share them. <p>
+ *
+ * @author Edwin Smith, Macromedia
+ */
+public class ParamReader
+ extends ClassReader {
+ private String methodName;
+ private Map methods = new HashMap();
+ private Class[] paramTypes;
+
+ /**
+ * process a class file, given it's class. We'll use the defining
+ * classloader to locate the bytecode.
+ * @param c
+ * @throws IOException
+ */
+ public ParamReader(Class c) throws IOException {
+ this(getBytes(c));
+ }
+
+ /**
+ * process the given class bytes directly.
+ * @param b
+ * @throws IOException
+ */
+ public ParamReader(byte[] b) throws IOException {
+ super(b, findAttributeReaders(ParamReader.class));
+
+ // check the magic number
+ if (readInt() != 0xCAFEBABE) {
+ // not a class file!
+ throw new IOException("badClassFile");
+ }
+
+ readShort(); // minor version
+ readShort(); // major version
+
+ readCpool(); // slurp in the constant pool
+
+ readShort(); // access flags
+ readShort(); // this class name
+ readShort(); // super class name
+
+ int count = readShort(); // ifaces count
+ for (int i = 0; i < count; i++) {
+ readShort(); // interface index
+ }
+
+ count = readShort(); // fields count
+ for (int i = 0; i < count; i++) {
+ readShort(); // access flags
+ readShort(); // name index
+ readShort(); // descriptor index
+ skipAttributes(); // field attributes
+ }
+
+ count = readShort(); // methods count
+ for (int i = 0; i < count; i++) {
+ readShort(); // access flags
+ int m = readShort(); // name index
+ String name = resolveUtf8(m);
+ int d = readShort(); // descriptor index
+ this.methodName = name + resolveUtf8(d);
+ readAttributes(); // method attributes
+ }
+
+ }
+
+ public void readCode() throws IOException
+ {
+ readShort(); // max stack
+ int maxLocals = readShort(); // max locals
+
+ MethodInfo info = new MethodInfo(maxLocals);
+ if (methods != null && methodName != null)
+ {
+ methods.put(methodName, info);
+ }
+
+ skipFully(readInt()); // code
+ skipFully(8 * readShort()); // exception table
+ // read the code attributes (recursive). This is where
+ // we will find the LocalVariableTable attribute.
+ readAttributes();
+ }
+
+ /**
+ * return the names of the declared parameters for the given constructor.
+ * If we cannot determine the names, return null. The returned array will
+ * have one name per parameter. The length of the array will be the same
+ * as the length of the Class[] array returned by Constructor.getParameterTypes().
+ * @param ctor
+ * @return String[] array of names, one per parameter, or null
+ */
+ public String[] getParameterNames(Constructor ctor) {
+ paramTypes = ctor.getParameterTypes();
+ return getParameterNames(ctor, paramTypes);
+ }
+
+ /**
+ * return the names of the declared parameters for the given method.
+ * If we cannot determine the names, return null. The returned array will
+ * have one name per parameter. The length of the array will be the same
+ * as the length of the Class[] array returned by Method.getParameterTypes().
+ * @param method
+ * @return String[] array of names, one per parameter, or null
+ */
+ public String[] getParameterNames(Method method) {
+ paramTypes = method.getParameterTypes();
+ return getParameterNames(method, paramTypes);
+ }
+
+ protected String[] getParameterNames(Member member,Class [] paramTypes) {
+ // look up the names for this method
+ MethodInfo info = (MethodInfo) methods.get(getSignature(member, paramTypes));
+
+ // we know all the local variable names, but we only need to return
+ // the names of the parameters.
+
+ if (info != null) {
+ String[] paramNames = new String[paramTypes.length];
+ int j = Modifier.isStatic(member.getModifiers()) ? 0 : 1;
+
+ boolean found = false; // did we find any non-null names
+ for (int i = 0; i < paramNames.length; i++) {
+ if (info.names[j] != null) {
+ found = true;
+ paramNames[i] = info.names[j];
+ }
+ j++;
+ if (paramTypes[i] == double.class || paramTypes[i] == long.class) {
+ // skip a slot for 64bit params
+ j++;
+ }
+ }
+
+ if (found) {
+ return paramNames;
+ } else {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ private static class MethodInfo
+ {
+ String[] names;
+ int maxLocals;
+
+ public MethodInfo(int maxLocals)
+ {
+ this.maxLocals = maxLocals;
+ names = new String[maxLocals];
+ }
+ }
+
+ private MethodInfo getMethodInfo()
+ {
+ MethodInfo info = null;
+ if (methods != null && methodName != null)
+ {
+ info = (MethodInfo) methods.get(methodName);
+ }
+ return info;
+ }
+
+ /**
+ * this is invoked when a LocalVariableTable attribute is encountered.
+ * @throws IOException
+ */
+ public void readLocalVariableTable() throws IOException {
+ int len = readShort(); // table length
+ MethodInfo info = getMethodInfo();
+ for (int j = 0; j < len; j++) {
+ readShort(); // start pc
+ readShort(); // length
+ int nameIndex = readShort(); // name_index
+ readShort(); // descriptor_index
+ int index = readShort(); // local index
+ if (info != null) {
+ info.names[index] = resolveUtf8(nameIndex);
+ }
+ }
+ }
+}
\ No newline at end of file