View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  package org.apache.bcel.classfile;
18  
19  import java.io.DataInput;
20  import java.io.IOException;
21  import java.util.Objects;
22  
23  import org.apache.bcel.generic.Type;
24  import org.apache.bcel.util.BCELComparator;
25  
26  /**
27   * This class represents the method info structure, i.e., the representation for a method in the class. See JVM
28   * specification for details. A method has access flags, a name, a signature and a number of attributes.
29   */
30  public final class Method extends FieldOrMethod {
31  
32      /**
33       * Empty array constant.
34       *
35       * @since 6.6.0
36       */
37      public static final Method[] EMPTY_ARRAY = {};
38  
39      private static BCELComparator<Method> bcelComparator = new BCELComparator<Method>() {
40  
41          @Override
42          public boolean equals(final Method a, final Method b) {
43              return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature());
44          }
45  
46          @Override
47          public int hashCode(final Method o) {
48              return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0;
49          }
50      };
51  
52      /**
53       * Empty array.
54       */
55      static final Method[] EMPTY_METHOD_ARRAY = {};
56  
57      /**
58       * @return Comparison strategy object.
59       */
60      public static BCELComparator<Method> getComparator() {
61          return bcelComparator;
62      }
63  
64      /**
65       * @param comparator Comparison strategy object.
66       */
67      public static void setComparator(final BCELComparator<Method> comparator) {
68          bcelComparator = comparator;
69      }
70  
71      /** Annotations defined on the parameters of a method. */
72      private ParameterAnnotationEntry[] parameterAnnotationEntries;
73  
74      /**
75       * Empty constructor, all attributes have to be defined via 'setXXX' methods. Use at your own risk.
76       */
77      public Method() {
78      }
79  
80      /**
81       * Constructs object from file stream.
82       *
83       * @param file Input stream
84       * @throws IOException if an I/O error occurs.
85       * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
86       */
87      Method(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException {
88          super(file, constantPool);
89      }
90  
91      /**
92       * @param accessFlags Access rights of method
93       * @param nameIndex Points to field name in constant pool
94       * @param signatureIndex Points to encoded signature
95       * @param attributes Collection of attributes
96       * @param constantPool Array of constants
97       */
98      public Method(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) {
99          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 }