1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * https://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.bcel.classfile;
20
21 import java.io.DataInput;
22 import java.io.IOException;
23 import java.util.Objects;
24
25 import org.apache.bcel.generic.Type;
26 import org.apache.bcel.util.BCELComparator;
27
28 /**
29 * This class represents the method info structure, that is, the representation for a method in the class. See JVM
30 * specification for details. A method has access flags, a name, a signature and a number of attributes.
31 */
32 public final class Method extends FieldOrMethod {
33
34 /**
35 * Empty array constant.
36 *
37 * @since 6.6.0
38 */
39 public static final Method[] EMPTY_ARRAY = {};
40
41 private static BCELComparator<Method> bcelComparator = new BCELComparator<Method>() {
42
43 @Override
44 public boolean equals(final Method a, final Method b) {
45 return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature());
46 }
47
48 @Override
49 public int hashCode(final Method o) {
50 return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0;
51 }
52 };
53
54 /**
55 * Gets the comparison strategy object.
56 *
57 * @return Comparison strategy object.
58 */
59 public static BCELComparator<Method> getComparator() {
60 return bcelComparator;
61 }
62
63 /**
64 * Sets the comparison strategy object.
65 *
66 * @param comparator Comparison strategy object.
67 */
68 public static void setComparator(final BCELComparator<Method> comparator) {
69 bcelComparator = comparator;
70 }
71
72 /** Annotations defined on the parameters of a method. */
73 private ParameterAnnotationEntry[] parameterAnnotationEntries;
74
75 /**
76 * Empty constructor, all attributes have to be defined via 'setXXX' methods. Use at your own risk.
77 */
78 public Method() {
79 }
80
81 /**
82 * Constructs object from file stream.
83 *
84 * @param file Input stream.
85 * @throws IOException if an I/O error occurs.
86 * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file.
87 */
88 Method(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException {
89 super(file, constantPool);
90 }
91
92 /**
93 * Constructs a Method.
94 *
95 * @param accessFlags Access rights of method.
96 * @param nameIndex Points to field name in constant pool.
97 * @param signatureIndex Points to encoded signature.
98 * @param attributes Collection of attributes.
99 * @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 * Creates a deep copy of this method.
128 *
129 * @param constantPool the constant pool.
130 * @return deep copy of this method.
131 */
132 public Method copy(final ConstantPool constantPool) {
133 return (Method) copy_(constantPool);
134 }
135
136 /**
137 * Return value as defined by given BCELComparator strategy. By default two method objects are said to be equal when
138 * their names and signatures are equal.
139 *
140 * @see Object#equals(Object)
141 */
142 @Override
143 public boolean equals(final Object obj) {
144 return obj instanceof Method && bcelComparator.equals(this, (Method) obj);
145 }
146
147 /**
148 * Gets array of method argument types.
149 *
150 * @return array of method argument types.
151 */
152 public Type[] getArgumentTypes() {
153 return Type.getArgumentTypes(getSignature());
154 }
155
156 /**
157 * Gets Code attribute of method, if any.
158 *
159 * @return Code attribute of method, if any.
160 */
161 public Code getCode() {
162 for (final Attribute attribute : super.getAttributes()) {
163 if (attribute instanceof Code) {
164 return (Code) attribute;
165 }
166 }
167 return null;
168 }
169
170 /**
171 * Gets ExceptionTable attribute of method, if any.
172 *
173 * @return ExceptionTable attribute of method, if any, that is, list all exceptions the method may throw not exception handlers.
174 */
175 public ExceptionTable getExceptionTable() {
176 for (final Attribute attribute : super.getAttributes()) {
177 if (attribute instanceof ExceptionTable) {
178 return (ExceptionTable) attribute;
179 }
180 }
181 return null;
182 }
183
184 /**
185 * Gets LineNumberTable of code attribute if any.
186 *
187 * @return LineNumberTable of code attribute if any, for example the call is forwarded to the Code attribute.
188 */
189 public LineNumberTable getLineNumberTable() {
190 final Code code = getCode();
191 if (code == null) {
192 return null;
193 }
194 return code.getLineNumberTable();
195 }
196
197 /**
198 * Gets LocalVariableTable of code attribute if any.
199 *
200 * @return LocalVariableTable of code attribute if any, for example the call is forwarded to the Code attribute.
201 */
202 public LocalVariableTable getLocalVariableTable() {
203 final Code code = getCode();
204 if (code == null) {
205 return null;
206 }
207 return code.getLocalVariableTable();
208 }
209
210 /**
211 * Gets the local variable type table attribute {@link LocalVariableTypeTable}.
212 *
213 * @return LocalVariableTypeTable of code attribute if any, for example the call is forwarded to the Code attribute.
214 * @since 6.10.0
215 */
216 public LocalVariableTypeTable getLocalVariableTypeTable() {
217 final Code code = getCode();
218 if (code == null) {
219 return null;
220 }
221 return code.getLocalVariableTypeTable();
222 }
223
224 /**
225 * Gets Annotations on the parameters of a method.
226 *
227 * @return Annotations on the parameters of a method.
228 * @since 6.0
229 */
230 public ParameterAnnotationEntry[] getParameterAnnotationEntries() {
231 if (parameterAnnotationEntries == null) {
232 parameterAnnotationEntries = ParameterAnnotationEntry.createParameterAnnotationEntries(getAttributes());
233 }
234 return parameterAnnotationEntries;
235 }
236
237 /**
238 * Gets return type of method.
239 *
240 * @return return type of method.
241 */
242 public Type getReturnType() {
243 return Type.getReturnType(getSignature());
244 }
245
246 /**
247 * Return value as defined by given BCELComparator strategy. By default return the hash code of the method's name XOR
248 * signature.
249 *
250 * @see Object#hashCode()
251 */
252 @Override
253 public int hashCode() {
254 return bcelComparator.hashCode(this);
255 }
256
257 /**
258 * Return string representation close to declaration format, 'public static void main(String[] args) throws
259 * IOException', for example.
260 *
261 * @return String representation of the method.
262 */
263 @Override
264 public String toString() {
265 final String access = Utility.accessToString(super.getAccessFlags());
266 // Get name and signature from constant pool
267 ConstantUtf8 c = super.getConstantPool().getConstantUtf8(super.getSignatureIndex());
268 String signature = c.getBytes();
269 c = super.getConstantPool().getConstantUtf8(super.getNameIndex());
270 final String name = c.getBytes();
271 signature = Utility.methodSignatureToString(signature, name, access, true, getLocalVariableTable());
272 final StringBuilder buf = new StringBuilder(signature);
273 for (final Attribute attribute : super.getAttributes()) {
274 if (!(attribute instanceof Code || attribute instanceof ExceptionTable)) {
275 buf.append(" [").append(attribute).append("]");
276 }
277 }
278 final ExceptionTable e = getExceptionTable();
279 if (e != null) {
280 final String str = e.toString();
281 if (!str.isEmpty()) {
282 buf.append("\n\t\tthrows ").append(str);
283 }
284 }
285 return buf.toString();
286 }
287 }
288