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