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       * @return Comparison strategy object.
54       */
55      public static BCELComparator<Method> getComparator() {
56          return bcelComparator;
57      }
58  
59      /**
60       * @param comparator Comparison strategy object.
61       */
62      public static void setComparator(final BCELComparator<Method> comparator) {
63          bcelComparator = comparator;
64      }
65  
66      /** Annotations defined on the parameters of a method. */
67      private ParameterAnnotationEntry[] parameterAnnotationEntries;
68  
69      /**
70       * Empty constructor, all attributes have to be defined via 'setXXX' methods. Use at your own risk.
71       */
72      public Method() {
73      }
74  
75      /**
76       * Constructs object from file stream.
77       *
78       * @param file Input stream
79       * @throws IOException if an I/O error occurs.
80       * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
81       */
82      Method(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException {
83          super(file, constantPool);
84      }
85  
86      /**
87       * @param accessFlags Access rights of method
88       * @param nameIndex Points to field name in constant pool
89       * @param signatureIndex Points to encoded signature
90       * @param attributes Collection of attributes
91       * @param constantPool Array of constants
92       */
93      public Method(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) {
94          super(accessFlags, nameIndex, signatureIndex, attributes, constantPool);
95      }
96  
97      /**
98       * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
99       * physical copy.
100      *
101      * @param c Source to copy.
102      */
103     public Method(final Method c) {
104         super(c);
105     }
106 
107     /**
108      * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
109      * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
110      *
111      * @param v Visitor object
112      */
113     @Override
114     public void accept(final Visitor v) {
115         v.visitMethod(this);
116     }
117 
118     /**
119      * @return deep copy of this method
120      */
121     public Method copy(final ConstantPool constantPool) {
122         return (Method) copy_(constantPool);
123     }
124 
125     /**
126      * Return value as defined by given BCELComparator strategy. By default two method objects are said to be equal when
127      * their names and signatures are equal.
128      *
129      * @see Object#equals(Object)
130      */
131     @Override
132     public boolean equals(final Object obj) {
133         return obj instanceof Method && bcelComparator.equals(this, (Method) obj);
134     }
135 
136     /**
137      * @return array of method argument types
138      */
139     public Type[] getArgumentTypes() {
140         return Type.getArgumentTypes(getSignature());
141     }
142 
143     /**
144      * @return Code attribute of method, if any
145      */
146     public Code getCode() {
147         for (final Attribute attribute : super.getAttributes()) {
148             if (attribute instanceof Code) {
149                 return (Code) attribute;
150             }
151         }
152         return null;
153     }
154 
155     /**
156      * @return ExceptionTable attribute of method, if any, i.e., list all exceptions the method may throw not exception
157      *         handlers!
158      */
159     public ExceptionTable getExceptionTable() {
160         for (final Attribute attribute : super.getAttributes()) {
161             if (attribute instanceof ExceptionTable) {
162                 return (ExceptionTable) attribute;
163             }
164         }
165         return null;
166     }
167 
168     /**
169      * @return LineNumberTable of code attribute if any, i.e. the call is forwarded to the Code atribute.
170      */
171     public LineNumberTable getLineNumberTable() {
172         final Code code = getCode();
173         if (code == null) {
174             return null;
175         }
176         return code.getLineNumberTable();
177     }
178 
179     /**
180      * @return LocalVariableTable of code attribute if any, i.e. the call is forwarded to the Code atribute.
181      */
182     public LocalVariableTable getLocalVariableTable() {
183         final Code code = getCode();
184         if (code == null) {
185             return null;
186         }
187         return code.getLocalVariableTable();
188     }
189 
190     /**
191      * @return Annotations on the parameters of a method
192      * @since 6.0
193      */
194     public ParameterAnnotationEntry[] getParameterAnnotationEntries() {
195         if (parameterAnnotationEntries == null) {
196             parameterAnnotationEntries = ParameterAnnotationEntry.createParameterAnnotationEntries(getAttributes());
197         }
198         return parameterAnnotationEntries;
199     }
200 
201     /**
202      * @return return type of method
203      */
204     public Type getReturnType() {
205         return Type.getReturnType(getSignature());
206     }
207 
208     /**
209      * Return value as defined by given BCELComparator strategy. By default return the hash code of the method's name XOR
210      * signature.
211      *
212      * @see Object#hashCode()
213      */
214     @Override
215     public int hashCode() {
216         return bcelComparator.hashCode(this);
217     }
218 
219     /**
220      * Return string representation close to declaration format, 'public static void main(String[] args) throws
221      * IOException', e.g.
222      *
223      * @return String representation of the method.
224      */
225     @Override
226     public String toString() {
227         final String access = Utility.accessToString(super.getAccessFlags());
228         // Get name and signature from constant pool
229         ConstantUtf8 c = super.getConstantPool().getConstantUtf8(super.getSignatureIndex());
230         String signature = c.getBytes();
231         c = super.getConstantPool().getConstantUtf8(super.getNameIndex());
232         final String name = c.getBytes();
233         signature = Utility.methodSignatureToString(signature, name, access, true, getLocalVariableTable());
234         final StringBuilder buf = new StringBuilder(signature);
235         for (final Attribute attribute : super.getAttributes()) {
236             if (!(attribute instanceof Code || attribute instanceof ExceptionTable)) {
237                 buf.append(" [").append(attribute).append("]");
238             }
239         }
240         final ExceptionTable e = getExceptionTable();
241         if (e != null) {
242             final String str = e.toString();
243             if (!str.isEmpty()) {
244                 buf.append("\n\t\tthrows ").append(str);
245             }
246         }
247         return buf.toString();
248     }
249 }