001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.bcel.classfile; 018 019import java.io.DataInput; 020import java.io.IOException; 021import java.util.Objects; 022 023import org.apache.bcel.generic.Type; 024import org.apache.bcel.util.BCELComparator; 025 026/** 027 * This class represents the method info structure, i.e., the representation for a method in the class. See JVM 028 * specification for details. A method has access flags, a name, a signature and a number of attributes. 029 */ 030public final class Method extends FieldOrMethod { 031 032 /** 033 * Empty array constant. 034 * 035 * @since 6.6.0 036 */ 037 public static final Method[] EMPTY_ARRAY = {}; 038 039 private static BCELComparator<Method> bcelComparator = new BCELComparator<Method>() { 040 041 @Override 042 public boolean equals(final Method a, final Method b) { 043 return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature()); 044 } 045 046 @Override 047 public int hashCode(final Method o) { 048 return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0; 049 } 050 }; 051 052 /** 053 * Empty array. 054 */ 055 static final Method[] EMPTY_METHOD_ARRAY = {}; 056 057 /** 058 * @return Comparison strategy object. 059 */ 060 public static BCELComparator<Method> getComparator() { 061 return bcelComparator; 062 } 063 064 /** 065 * @param comparator Comparison strategy object. 066 */ 067 public static void setComparator(final BCELComparator<Method> comparator) { 068 bcelComparator = comparator; 069 } 070 071 /** Annotations defined on the parameters of a method. */ 072 private ParameterAnnotationEntry[] parameterAnnotationEntries; 073 074 /** 075 * Empty constructor, all attributes have to be defined via 'setXXX' methods. Use at your own risk. 076 */ 077 public Method() { 078 } 079 080 /** 081 * Constructs object from file stream. 082 * 083 * @param file Input stream 084 * @throws IOException if an I/O error occurs. 085 * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file 086 */ 087 Method(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException { 088 super(file, constantPool); 089 } 090 091 /** 092 * @param accessFlags Access rights of method 093 * @param nameIndex Points to field name in constant pool 094 * @param signatureIndex Points to encoded signature 095 * @param attributes Collection of attributes 096 * @param constantPool Array of constants 097 */ 098 public Method(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) { 099 super(accessFlags, nameIndex, signatureIndex, attributes, constantPool); 100 } 101 102 /** 103 * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a 104 * physical copy. 105 * 106 * @param c Source to copy. 107 */ 108 public Method(final Method c) { 109 super(c); 110 } 111 112 /** 113 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. 114 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. 115 * 116 * @param v Visitor object 117 */ 118 @Override 119 public void accept(final Visitor v) { 120 v.visitMethod(this); 121 } 122 123 /** 124 * @return deep copy of this method 125 */ 126 public Method copy(final ConstantPool constantPool) { 127 return (Method) copy_(constantPool); 128 } 129 130 /** 131 * Return value as defined by given BCELComparator strategy. By default two method objects are said to be equal when 132 * their names and signatures are equal. 133 * 134 * @see Object#equals(Object) 135 */ 136 @Override 137 public boolean equals(final Object obj) { 138 return obj instanceof Method && bcelComparator.equals(this, (Method) obj); 139 } 140 141 /** 142 * @return array of method argument types 143 */ 144 public Type[] getArgumentTypes() { 145 return Type.getArgumentTypes(getSignature()); 146 } 147 148 /** 149 * @return Code attribute of method, if any 150 */ 151 public Code getCode() { 152 for (final Attribute attribute : super.getAttributes()) { 153 if (attribute instanceof Code) { 154 return (Code) attribute; 155 } 156 } 157 return null; 158 } 159 160 /** 161 * @return ExceptionTable attribute of method, if any, i.e., list all exceptions the method may throw not exception 162 * handlers! 163 */ 164 public ExceptionTable getExceptionTable() { 165 for (final Attribute attribute : super.getAttributes()) { 166 if (attribute instanceof ExceptionTable) { 167 return (ExceptionTable) attribute; 168 } 169 } 170 return null; 171 } 172 173 /** 174 * @return LineNumberTable of code attribute if any, i.e. the call is forwarded to the Code atribute. 175 */ 176 public LineNumberTable getLineNumberTable() { 177 final Code code = getCode(); 178 if (code == null) { 179 return null; 180 } 181 return code.getLineNumberTable(); 182 } 183 184 /** 185 * @return LocalVariableTable of code attribute if any, i.e. the call is forwarded to the Code atribute. 186 */ 187 public LocalVariableTable getLocalVariableTable() { 188 final Code code = getCode(); 189 if (code == null) { 190 return null; 191 } 192 return code.getLocalVariableTable(); 193 } 194 195 /** 196 * @return Annotations on the parameters of a method 197 * @since 6.0 198 */ 199 public ParameterAnnotationEntry[] getParameterAnnotationEntries() { 200 if (parameterAnnotationEntries == null) { 201 parameterAnnotationEntries = ParameterAnnotationEntry.createParameterAnnotationEntries(getAttributes()); 202 } 203 return parameterAnnotationEntries; 204 } 205 206 /** 207 * @return return type of method 208 */ 209 public Type getReturnType() { 210 return Type.getReturnType(getSignature()); 211 } 212 213 /** 214 * Return value as defined by given BCELComparator strategy. By default return the hash code of the method's name XOR 215 * signature. 216 * 217 * @see Object#hashCode() 218 */ 219 @Override 220 public int hashCode() { 221 return bcelComparator.hashCode(this); 222 } 223 224 /** 225 * Return string representation close to declaration format, 'public static void main(String[] args) throws 226 * IOException', e.g. 227 * 228 * @return String representation of the method. 229 */ 230 @Override 231 public String toString() { 232 final String access = Utility.accessToString(super.getAccessFlags()); 233 // Get name and signature from constant pool 234 ConstantUtf8 c = super.getConstantPool().getConstantUtf8(super.getSignatureIndex()); 235 String signature = c.getBytes(); 236 c = super.getConstantPool().getConstantUtf8(super.getNameIndex()); 237 final String name = c.getBytes(); 238 signature = Utility.methodSignatureToString(signature, name, access, true, getLocalVariableTable()); 239 final StringBuilder buf = new StringBuilder(signature); 240 for (final Attribute attribute : super.getAttributes()) { 241 if (!(attribute instanceof Code || attribute instanceof ExceptionTable)) { 242 buf.append(" [").append(attribute).append("]"); 243 } 244 } 245 final ExceptionTable e = getExceptionTable(); 246 if (e != null) { 247 final String str = e.toString(); 248 if (!str.isEmpty()) { 249 buf.append("\n\t\tthrows ").append(str); 250 } 251 } 252 return buf.toString(); 253 } 254}