• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // ASM: a very small and fast Java bytecode manipulation framework
2 // Copyright (c) 2000-2011 INRIA, France Telecom
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions
7 // are met:
8 // 1. Redistributions of source code must retain the above copyright
9 //    notice, this list of conditions and the following disclaimer.
10 // 2. Redistributions in binary form must reproduce the above copyright
11 //    notice, this list of conditions and the following disclaimer in the
12 //    documentation and/or other materials provided with the distribution.
13 // 3. Neither the name of the copyright holders nor the names of its
14 //    contributors may be used to endorse or promote products derived from
15 //    this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 // THE POSSIBILITY OF SUCH DAMAGE.
28 package org.objectweb.asm.commons;
29 
30 import java.util.HashMap;
31 import java.util.Map;
32 import org.objectweb.asm.Type;
33 
34 /**
35  * A named method descriptor.
36  *
37  * @author Juozas Baliuka
38  * @author Chris Nokleberg
39  * @author Eric Bruneton
40  */
41 public class Method {
42 
43   /** The method name. */
44   private final String name;
45 
46   /** The method descriptor. */
47   private final String descriptor;
48 
49   /** The descriptors of the primitive Java types (plus void). */
50   private static final Map<String, String> PRIMITIVE_TYPE_DESCRIPTORS;
51 
52   static {
53     HashMap<String, String> descriptors = new HashMap<>();
54     descriptors.put("void", "V");
55     descriptors.put("byte", "B");
56     descriptors.put("char", "C");
57     descriptors.put("double", "D");
58     descriptors.put("float", "F");
59     descriptors.put("int", "I");
60     descriptors.put("long", "J");
61     descriptors.put("short", "S");
62     descriptors.put("boolean", "Z");
63     PRIMITIVE_TYPE_DESCRIPTORS = descriptors;
64   }
65 
66   /**
67    * Constructs a new {@link Method}.
68    *
69    * @param name the method's name.
70    * @param descriptor the method's descriptor.
71    */
Method(final String name, final String descriptor)72   public Method(final String name, final String descriptor) {
73     this.name = name;
74     this.descriptor = descriptor;
75   }
76 
77   /**
78    * Constructs a new {@link Method}.
79    *
80    * @param name the method's name.
81    * @param returnType the method's return type.
82    * @param argumentTypes the method's argument types.
83    */
Method(final String name, final Type returnType, final Type[] argumentTypes)84   public Method(final String name, final Type returnType, final Type[] argumentTypes) {
85     this(name, Type.getMethodDescriptor(returnType, argumentTypes));
86   }
87 
88   /**
89    * Creates a new {@link Method}.
90    *
91    * @param method a java.lang.reflect method descriptor
92    * @return a {@link Method} corresponding to the given Java method declaration.
93    */
getMethod(final java.lang.reflect.Method method)94   public static Method getMethod(final java.lang.reflect.Method method) {
95     return new Method(method.getName(), Type.getMethodDescriptor(method));
96   }
97 
98   /**
99    * Creates a new {@link Method}.
100    *
101    * @param constructor a java.lang.reflect constructor descriptor
102    * @return a {@link Method} corresponding to the given Java constructor declaration.
103    */
getMethod(final java.lang.reflect.Constructor<?> constructor)104   public static Method getMethod(final java.lang.reflect.Constructor<?> constructor) {
105     return new Method("<init>", Type.getConstructorDescriptor(constructor));
106   }
107 
108   /**
109    * Returns a {@link Method} corresponding to the given Java method declaration.
110    *
111    * @param method a Java method declaration, without argument names, of the form "returnType name
112    *     (argumentType1, ... argumentTypeN)", where the types are in plain Java (e.g. "int",
113    *     "float", "java.util.List", ...). Classes of the java.lang package can be specified by their
114    *     unqualified name; all other classes names must be fully qualified.
115    * @return a {@link Method} corresponding to the given Java method declaration.
116    * @throws IllegalArgumentException if <code>method</code> could not get parsed.
117    */
getMethod(final String method)118   public static Method getMethod(final String method) {
119     return getMethod(method, false);
120   }
121 
122   /**
123    * Returns a {@link Method} corresponding to the given Java method declaration.
124    *
125    * @param method a Java method declaration, without argument names, of the form "returnType name
126    *     (argumentType1, ... argumentTypeN)", where the types are in plain Java (e.g. "int",
127    *     "float", "java.util.List", ...). Classes of the java.lang package may be specified by their
128    *     unqualified name, depending on the defaultPackage argument; all other classes names must be
129    *     fully qualified.
130    * @param defaultPackage true if unqualified class names belong to the default package, or false
131    *     if they correspond to java.lang classes. For instance "Object" means "Object" if this
132    *     option is true, or "java.lang.Object" otherwise.
133    * @return a {@link Method} corresponding to the given Java method declaration.
134    * @throws IllegalArgumentException if <code>method</code> could not get parsed.
135    */
getMethod(final String method, final boolean defaultPackage)136   public static Method getMethod(final String method, final boolean defaultPackage) {
137     final int spaceIndex = method.indexOf(' ');
138     int currentArgumentStartIndex = method.indexOf('(', spaceIndex) + 1;
139     final int endIndex = method.indexOf(')', currentArgumentStartIndex);
140     if (spaceIndex == -1 || currentArgumentStartIndex == 0 || endIndex == -1) {
141       throw new IllegalArgumentException();
142     }
143     final String returnType = method.substring(0, spaceIndex);
144     final String methodName =
145         method.substring(spaceIndex + 1, currentArgumentStartIndex - 1).trim();
146     StringBuilder stringBuilder = new StringBuilder();
147     stringBuilder.append('(');
148     int currentArgumentEndIndex;
149     do {
150       String argumentDescriptor;
151       currentArgumentEndIndex = method.indexOf(',', currentArgumentStartIndex);
152       if (currentArgumentEndIndex == -1) {
153         argumentDescriptor =
154             getDescriptorInternal(
155                 method.substring(currentArgumentStartIndex, endIndex).trim(), defaultPackage);
156       } else {
157         argumentDescriptor =
158             getDescriptorInternal(
159                 method.substring(currentArgumentStartIndex, currentArgumentEndIndex).trim(),
160                 defaultPackage);
161         currentArgumentStartIndex = currentArgumentEndIndex + 1;
162       }
163       stringBuilder.append(argumentDescriptor);
164     } while (currentArgumentEndIndex != -1);
165     stringBuilder.append(')').append(getDescriptorInternal(returnType, defaultPackage));
166     return new Method(methodName, stringBuilder.toString());
167   }
168 
169   /**
170    * Returns the descriptor corresponding to the given type name.
171    *
172    * @param type a Java type name.
173    * @param defaultPackage true if unqualified class names belong to the default package, or false
174    *     if they correspond to java.lang classes. For instance "Object" means "Object" if this
175    *     option is true, or "java.lang.Object" otherwise.
176    * @return the descriptor corresponding to the given type name.
177    */
getDescriptorInternal(final String type, final boolean defaultPackage)178   private static String getDescriptorInternal(final String type, final boolean defaultPackage) {
179     if ("".equals(type)) {
180       return type;
181     }
182 
183     StringBuilder stringBuilder = new StringBuilder();
184     int arrayBracketsIndex = 0;
185     while ((arrayBracketsIndex = type.indexOf("[]", arrayBracketsIndex) + 1) > 0) {
186       stringBuilder.append('[');
187     }
188 
189     String elementType = type.substring(0, type.length() - stringBuilder.length() * 2);
190     String descriptor = PRIMITIVE_TYPE_DESCRIPTORS.get(elementType);
191     if (descriptor != null) {
192       stringBuilder.append(descriptor);
193     } else {
194       stringBuilder.append('L');
195       if (elementType.indexOf('.') < 0) {
196         if (!defaultPackage) {
197           stringBuilder.append("java/lang/");
198         }
199         stringBuilder.append(elementType);
200       } else {
201         stringBuilder.append(elementType.replace('.', '/'));
202       }
203       stringBuilder.append(';');
204     }
205     return stringBuilder.toString();
206   }
207 
208   /**
209    * Returns the name of the method described by this object.
210    *
211    * @return the name of the method described by this object.
212    */
getName()213   public String getName() {
214     return name;
215   }
216 
217   /**
218    * Returns the descriptor of the method described by this object.
219    *
220    * @return the descriptor of the method described by this object.
221    */
getDescriptor()222   public String getDescriptor() {
223     return descriptor;
224   }
225 
226   /**
227    * Returns the return type of the method described by this object.
228    *
229    * @return the return type of the method described by this object.
230    */
getReturnType()231   public Type getReturnType() {
232     return Type.getReturnType(descriptor);
233   }
234 
235   /**
236    * Returns the argument types of the method described by this object.
237    *
238    * @return the argument types of the method described by this object.
239    */
getArgumentTypes()240   public Type[] getArgumentTypes() {
241     return Type.getArgumentTypes(descriptor);
242   }
243 
244   @Override
toString()245   public String toString() {
246     return name + descriptor;
247   }
248 
249   @Override
equals(final Object other)250   public boolean equals(final Object other) {
251     if (!(other instanceof Method)) {
252       return false;
253     }
254     Method otherMethod = (Method) other;
255     return name.equals(otherMethod.name) && descriptor.equals(otherMethod.descriptor);
256   }
257 
258   @Override
hashCode()259   public int hashCode() {
260     return name.hashCode() ^ descriptor.hashCode();
261   }
262 }
263