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 * Construct 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 public Method(final Method c) { 110 super(c); 111 } 112 113 /** 114 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. 115 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. 116 * 117 * @param v Visitor object 118 */ 119 @Override 120 public void accept(final Visitor v) { 121 v.visitMethod(this); 122 } 123 124 /** 125 * @return deep copy of this method 126 */ 127 public Method copy(final ConstantPool constantPool) { 128 return (Method) copy_(constantPool); 129 } 130 131 /** 132 * Return value as defined by given BCELComparator strategy. By default two method objects are said to be equal when 133 * their names and signatures are equal. 134 * 135 * @see Object#equals(Object) 136 */ 137 @Override 138 public boolean equals(final Object obj) { 139 return bcelComparator.equals(this, obj); 140 } 141 142 /** 143 * @return array of method argument types 144 */ 145 public Type[] getArgumentTypes() { 146 return Type.getArgumentTypes(getSignature()); 147 } 148 149 /** 150 * @return Code attribute of method, if any 151 */ 152 public Code getCode() { 153 for (final Attribute attribute : super.getAttributes()) { 154 if (attribute instanceof Code) { 155 return (Code) attribute; 156 } 157 } 158 return null; 159 } 160 161 /** 162 * @return ExceptionTable attribute of method, if any, i.e., list all exceptions the method may throw not exception 163 * handlers! 164 */ 165 public ExceptionTable getExceptionTable() { 166 for (final Attribute attribute : super.getAttributes()) { 167 if (attribute instanceof ExceptionTable) { 168 return (ExceptionTable) attribute; 169 } 170 } 171 return null; 172 } 173 174 /** 175 * @return LineNumberTable of code attribute if any, i.e. the call is forwarded to the Code atribute. 176 */ 177 public LineNumberTable getLineNumberTable() { 178 final Code code = getCode(); 179 if (code == null) { 180 return null; 181 } 182 return code.getLineNumberTable(); 183 } 184 185 /** 186 * @return LocalVariableTable of code attribute if any, i.e. the call is forwarded to the Code atribute. 187 */ 188 public LocalVariableTable getLocalVariableTable() { 189 final Code code = getCode(); 190 if (code == null) { 191 return null; 192 } 193 return code.getLocalVariableTable(); 194 } 195 196 /** 197 * @return Annotations on the parameters of a method 198 * @since 6.0 199 */ 200 public ParameterAnnotationEntry[] getParameterAnnotationEntries() { 201 if (parameterAnnotationEntries == null) { 202 parameterAnnotationEntries = ParameterAnnotationEntry.createParameterAnnotationEntries(getAttributes()); 203 } 204 return parameterAnnotationEntries; 205 } 206 207 /** 208 * @return return type of method 209 */ 210 public Type getReturnType() { 211 return Type.getReturnType(getSignature()); 212 } 213 214 /** 215 * Return value as defined by given BCELComparator strategy. By default return the hashcode of the method's name XOR 216 * signature. 217 * 218 * @see Object#hashCode() 219 */ 220 @Override 221 public int hashCode() { 222 return bcelComparator.hashCode(this); 223 } 224 225 /** 226 * Return string representation close to declaration format, `public static void main(String[] args) throws 227 * IOException', e.g. 228 * 229 * @return String representation of the method. 230 */ 231 @Override 232 public String toString() { 233 final String access = Utility.accessToString(super.getAccessFlags()); 234 // Get name and signature from constant pool 235 ConstantUtf8 c = super.getConstantPool().getConstantUtf8(super.getSignatureIndex()); 236 String signature = c.getBytes(); 237 c = super.getConstantPool().getConstantUtf8(super.getNameIndex()); 238 final String name = c.getBytes(); 239 signature = Utility.methodSignatureToString(signature, name, access, true, getLocalVariableTable()); 240 final StringBuilder buf = new StringBuilder(signature); 241 for (final Attribute attribute : super.getAttributes()) { 242 if (!(attribute instanceof Code || attribute instanceof ExceptionTable)) { 243 buf.append(" [").append(attribute).append("]"); 244 } 245 } 246 final ExceptionTable e = getExceptionTable(); 247 if (e != null) { 248 final String str = e.toString(); 249 if (!str.isEmpty()) { 250 buf.append("\n\t\tthrows ").append(str); 251 } 252 } 253 return buf.toString(); 254 } 255}