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 * 017 */ 018package org.apache.bcel.classfile; 019 020import java.io.DataInput; 021import java.io.IOException; 022import java.util.Objects; 023 024import org.apache.bcel.generic.Type; 025import org.apache.bcel.util.BCELComparator; 026 027/** 028 * This class represents the method info structure, i.e., the representation for a method in the class. See JVM 029 * specification for details. A method has access flags, a name, a signature and a number of attributes. 030 * 031 */ 032public final class Method extends FieldOrMethod { 033 034 /** 035 * Empty array constant. 036 * 037 * @since 6.6.0 038 */ 039 public static final Method[] EMPTY_ARRAY = {}; 040 041 private static BCELComparator bcelComparator = new BCELComparator() { 042 043 @Override 044 public boolean equals(final Object o1, final Object o2) { 045 final Method THIS = (Method) o1; 046 final Method THAT = (Method) o2; 047 return Objects.equals(THIS.getName(), THAT.getName()) && Objects.equals(THIS.getSignature(), THAT.getSignature()); 048 } 049 050 @Override 051 public int hashCode(final Object o) { 052 final Method THIS = (Method) o; 053 return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); 054 } 055 }; 056 057 /** 058 * Empty array. 059 */ 060 static final Method[] EMPTY_METHOD_ARRAY = {}; 061 062 /** 063 * @return Comparison strategy object 064 */ 065 public static BCELComparator getComparator() { 066 return bcelComparator; 067 } 068 069 /** 070 * @param comparator Comparison strategy object 071 */ 072 public static void setComparator(final BCELComparator comparator) { 073 bcelComparator = comparator; 074 } 075 076 // annotations defined on the parameters of a method 077 private ParameterAnnotationEntry[] parameterAnnotationEntries; 078 079 /** 080 * Empty constructor, all attributes have to be defined via `setXXX' methods. Use at your own risk. 081 */ 082 public Method() { 083 } 084 085 /** 086 * Construct object from file stream. 087 * 088 * @param file Input stream 089 * @throws IOException if an I/O error occurs. 090 * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file 091 */ 092 Method(final DataInput file, final ConstantPool constant_pool) throws IOException, ClassFormatException { 093 super(file, constant_pool); 094 } 095 096 /** 097 * @param access_flags Access rights of method 098 * @param name_index Points to field name in constant pool 099 * @param signature_index Points to encoded signature 100 * @param attributes Collection of attributes 101 * @param constant_pool Array of constants 102 */ 103 public Method(final int access_flags, final int name_index, final int signature_index, final Attribute[] attributes, final ConstantPool constant_pool) { 104 super(access_flags, name_index, signature_index, attributes, constant_pool); 105 } 106 107 /** 108 * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a 109 * physical 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 hashcode 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}