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 bcelComparator = new BCELComparator() { 040 041 @Override 042 public boolean equals(final Object o1, final Object o2) { 043 final Method THIS = (Method) o1; 044 final Method THAT = (Method) o2; 045 return Objects.equals(THIS.getName(), THAT.getName()) && Objects.equals(THIS.getSignature(), THAT.getSignature()); 046 } 047 048 @Override 049 public int hashCode(final Object o) { 050 final Method THIS = (Method) o; 051 return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); 052 } 053 }; 054 055 /** 056 * Empty array. 057 */ 058 static final Method[] EMPTY_METHOD_ARRAY = {}; 059 060 /** 061 * @return Comparison strategy object 062 */ 063 public static BCELComparator getComparator() { 064 return bcelComparator; 065 } 066 067 /** 068 * @param comparator Comparison strategy object 069 */ 070 public static void setComparator(final BCELComparator comparator) { 071 bcelComparator = comparator; 072 } 073 074 // annotations defined on the parameters of a method 075 private ParameterAnnotationEntry[] parameterAnnotationEntries; 076 077 /** 078 * Empty constructor, all attributes have to be defined via 'setXXX' methods. Use at your own risk. 079 */ 080 public Method() { 081 } 082 083 /** 084 * Constructs object from file stream. 085 * 086 * @param file Input stream 087 * @throws IOException if an I/O error occurs. 088 * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file 089 */ 090 Method(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException { 091 super(file, constantPool); 092 } 093 094 /** 095 * @param accessFlags Access rights of method 096 * @param nameIndex Points to field name in constant pool 097 * @param signatureIndex Points to encoded signature 098 * @param attributes Collection of attributes 099 * @param constantPool Array of constants 100 */ 101 public Method(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) { 102 super(accessFlags, nameIndex, signatureIndex, attributes, constantPool); 103 } 104 105 /** 106 * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a 107 * physical copy. 108 * 109 * @param c Source to copy. 110 */ 111 public Method(final Method c) { 112 super(c); 113 } 114 115 /** 116 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. 117 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. 118 * 119 * @param v Visitor object 120 */ 121 @Override 122 public void accept(final Visitor v) { 123 v.visitMethod(this); 124 } 125 126 /** 127 * @return deep copy of this method 128 */ 129 public Method copy(final ConstantPool constantPool) { 130 return (Method) copy_(constantPool); 131 } 132 133 /** 134 * Return value as defined by given BCELComparator strategy. By default two method objects are said to be equal when 135 * their names and signatures are equal. 136 * 137 * @see Object#equals(Object) 138 */ 139 @Override 140 public boolean equals(final Object obj) { 141 return bcelComparator.equals(this, obj); 142 } 143 144 /** 145 * @return array of method argument types 146 */ 147 public Type[] getArgumentTypes() { 148 return Type.getArgumentTypes(getSignature()); 149 } 150 151 /** 152 * @return Code attribute of method, if any 153 */ 154 public Code getCode() { 155 for (final Attribute attribute : super.getAttributes()) { 156 if (attribute instanceof Code) { 157 return (Code) attribute; 158 } 159 } 160 return null; 161 } 162 163 /** 164 * @return ExceptionTable attribute of method, if any, i.e., list all exceptions the method may throw not exception 165 * handlers! 166 */ 167 public ExceptionTable getExceptionTable() { 168 for (final Attribute attribute : super.getAttributes()) { 169 if (attribute instanceof ExceptionTable) { 170 return (ExceptionTable) attribute; 171 } 172 } 173 return null; 174 } 175 176 /** 177 * @return LineNumberTable of code attribute if any, i.e. the call is forwarded to the Code atribute. 178 */ 179 public LineNumberTable getLineNumberTable() { 180 final Code code = getCode(); 181 if (code == null) { 182 return null; 183 } 184 return code.getLineNumberTable(); 185 } 186 187 /** 188 * @return LocalVariableTable of code attribute if any, i.e. the call is forwarded to the Code atribute. 189 */ 190 public LocalVariableTable getLocalVariableTable() { 191 final Code code = getCode(); 192 if (code == null) { 193 return null; 194 } 195 return code.getLocalVariableTable(); 196 } 197 198 /** 199 * @return Annotations on the parameters of a method 200 * @since 6.0 201 */ 202 public ParameterAnnotationEntry[] getParameterAnnotationEntries() { 203 if (parameterAnnotationEntries == null) { 204 parameterAnnotationEntries = ParameterAnnotationEntry.createParameterAnnotationEntries(getAttributes()); 205 } 206 return parameterAnnotationEntries; 207 } 208 209 /** 210 * @return return type of method 211 */ 212 public Type getReturnType() { 213 return Type.getReturnType(getSignature()); 214 } 215 216 /** 217 * Return value as defined by given BCELComparator strategy. By default return the hash code of the method's name XOR 218 * signature. 219 * 220 * @see Object#hashCode() 221 */ 222 @Override 223 public int hashCode() { 224 return bcelComparator.hashCode(this); 225 } 226 227 /** 228 * Return string representation close to declaration format, 'public static void main(String[] args) throws 229 * IOException', e.g. 230 * 231 * @return String representation of the method. 232 */ 233 @Override 234 public String toString() { 235 final String access = Utility.accessToString(super.getAccessFlags()); 236 // Get name and signature from constant pool 237 ConstantUtf8 c = super.getConstantPool().getConstantUtf8(super.getSignatureIndex()); 238 String signature = c.getBytes(); 239 c = super.getConstantPool().getConstantUtf8(super.getNameIndex()); 240 final String name = c.getBytes(); 241 signature = Utility.methodSignatureToString(signature, name, access, true, getLocalVariableTable()); 242 final StringBuilder buf = new StringBuilder(signature); 243 for (final Attribute attribute : super.getAttributes()) { 244 if (!(attribute instanceof Code || attribute instanceof ExceptionTable)) { 245 buf.append(" [").append(attribute).append("]"); 246 } 247 } 248 final ExceptionTable e = getExceptionTable(); 249 if (e != null) { 250 final String str = e.toString(); 251 if (!str.isEmpty()) { 252 buf.append("\n\t\tthrows ").append(str); 253 } 254 } 255 return buf.toString(); 256 } 257}