Method.java

  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. import java.io.DataInput;
  19. import java.io.IOException;
  20. import java.util.Objects;

  21. import org.apache.bcel.generic.Type;
  22. import org.apache.bcel.util.BCELComparator;

  23. /**
  24.  * This class represents the method info structure, i.e., the representation for a method in the class. See JVM
  25.  * specification for details. A method has access flags, a name, a signature and a number of attributes.
  26.  */
  27. public final class Method extends FieldOrMethod {

  28.     /**
  29.      * Empty array constant.
  30.      *
  31.      * @since 6.6.0
  32.      */
  33.     public static final Method[] EMPTY_ARRAY = {};

  34.     private static BCELComparator<Method> bcelComparator = new BCELComparator<Method>() {

  35.         @Override
  36.         public boolean equals(final Method a, final Method b) {
  37.             return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature());
  38.         }

  39.         @Override
  40.         public int hashCode(final Method o) {
  41.             return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0;
  42.         }
  43.     };

  44.     /**
  45.      * @return Comparison strategy object.
  46.      */
  47.     public static BCELComparator<Method> getComparator() {
  48.         return bcelComparator;
  49.     }

  50.     /**
  51.      * @param comparator Comparison strategy object.
  52.      */
  53.     public static void setComparator(final BCELComparator<Method> comparator) {
  54.         bcelComparator = comparator;
  55.     }

  56.     /** Annotations defined on the parameters of a method. */
  57.     private ParameterAnnotationEntry[] parameterAnnotationEntries;

  58.     /**
  59.      * Empty constructor, all attributes have to be defined via 'setXXX' methods. Use at your own risk.
  60.      */
  61.     public Method() {
  62.     }

  63.     /**
  64.      * Constructs object from file stream.
  65.      *
  66.      * @param file Input stream
  67.      * @throws IOException if an I/O error occurs.
  68.      * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
  69.      */
  70.     Method(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException {
  71.         super(file, constantPool);
  72.     }

  73.     /**
  74.      * @param accessFlags Access rights of method
  75.      * @param nameIndex Points to field name in constant pool
  76.      * @param signatureIndex Points to encoded signature
  77.      * @param attributes Collection of attributes
  78.      * @param constantPool Array of constants
  79.      */
  80.     public Method(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) {
  81.         super(accessFlags, nameIndex, signatureIndex, attributes, constantPool);
  82.     }

  83.     /**
  84.      * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
  85.      * physical copy.
  86.      *
  87.      * @param c Source to copy.
  88.      */
  89.     public Method(final Method c) {
  90.         super(c);
  91.     }

  92.     /**
  93.      * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
  94.      * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
  95.      *
  96.      * @param v Visitor object
  97.      */
  98.     @Override
  99.     public void accept(final Visitor v) {
  100.         v.visitMethod(this);
  101.     }

  102.     /**
  103.      * @return deep copy of this method
  104.      */
  105.     public Method copy(final ConstantPool constantPool) {
  106.         return (Method) copy_(constantPool);
  107.     }

  108.     /**
  109.      * Return value as defined by given BCELComparator strategy. By default two method objects are said to be equal when
  110.      * their names and signatures are equal.
  111.      *
  112.      * @see Object#equals(Object)
  113.      */
  114.     @Override
  115.     public boolean equals(final Object obj) {
  116.         return obj instanceof Method && bcelComparator.equals(this, (Method) obj);
  117.     }

  118.     /**
  119.      * @return array of method argument types
  120.      */
  121.     public Type[] getArgumentTypes() {
  122.         return Type.getArgumentTypes(getSignature());
  123.     }

  124.     /**
  125.      * @return Code attribute of method, if any
  126.      */
  127.     public Code getCode() {
  128.         for (final Attribute attribute : super.getAttributes()) {
  129.             if (attribute instanceof Code) {
  130.                 return (Code) attribute;
  131.             }
  132.         }
  133.         return null;
  134.     }

  135.     /**
  136.      * @return ExceptionTable attribute of method, if any, i.e., list all exceptions the method may throw not exception
  137.      *         handlers!
  138.      */
  139.     public ExceptionTable getExceptionTable() {
  140.         for (final Attribute attribute : super.getAttributes()) {
  141.             if (attribute instanceof ExceptionTable) {
  142.                 return (ExceptionTable) attribute;
  143.             }
  144.         }
  145.         return null;
  146.     }

  147.     /**
  148.      * @return LineNumberTable of code attribute if any, i.e. the call is forwarded to the Code atribute.
  149.      */
  150.     public LineNumberTable getLineNumberTable() {
  151.         final Code code = getCode();
  152.         if (code == null) {
  153.             return null;
  154.         }
  155.         return code.getLineNumberTable();
  156.     }

  157.     /**
  158.      * @return LocalVariableTable of code attribute if any, i.e. the call is forwarded to the Code attribute.
  159.      */
  160.     public LocalVariableTable getLocalVariableTable() {
  161.         final Code code = getCode();
  162.         if (code == null) {
  163.             return null;
  164.         }
  165.         return code.getLocalVariableTable();
  166.     }

  167.     /**
  168.      * Gets the local variable type table attribute {@link LocalVariableTypeTable}.
  169.      * @return LocalVariableTypeTable of code attribute if any, i.e. the call is forwarded to the Code attribute.
  170.      * @since 6.10.0
  171.      */
  172.     public LocalVariableTypeTable getLocalVariableTypeTable() {
  173.         final Code code = getCode();
  174.         if (code == null) {
  175.             return null;
  176.         }
  177.         return code.getLocalVariableTypeTable();
  178.     }

  179.     /**
  180.      * @return Annotations on the parameters of a method
  181.      * @since 6.0
  182.      */
  183.     public ParameterAnnotationEntry[] getParameterAnnotationEntries() {
  184.         if (parameterAnnotationEntries == null) {
  185.             parameterAnnotationEntries = ParameterAnnotationEntry.createParameterAnnotationEntries(getAttributes());
  186.         }
  187.         return parameterAnnotationEntries;
  188.     }

  189.     /**
  190.      * @return return type of method
  191.      */
  192.     public Type getReturnType() {
  193.         return Type.getReturnType(getSignature());
  194.     }

  195.     /**
  196.      * Return value as defined by given BCELComparator strategy. By default return the hash code of the method's name XOR
  197.      * signature.
  198.      *
  199.      * @see Object#hashCode()
  200.      */
  201.     @Override
  202.     public int hashCode() {
  203.         return bcelComparator.hashCode(this);
  204.     }

  205.     /**
  206.      * Return string representation close to declaration format, 'public static void main(String[] args) throws
  207.      * IOException', e.g.
  208.      *
  209.      * @return String representation of the method.
  210.      */
  211.     @Override
  212.     public String toString() {
  213.         final String access = Utility.accessToString(super.getAccessFlags());
  214.         // Get name and signature from constant pool
  215.         ConstantUtf8 c = super.getConstantPool().getConstantUtf8(super.getSignatureIndex());
  216.         String signature = c.getBytes();
  217.         c = super.getConstantPool().getConstantUtf8(super.getNameIndex());
  218.         final String name = c.getBytes();
  219.         signature = Utility.methodSignatureToString(signature, name, access, true, getLocalVariableTable());
  220.         final StringBuilder buf = new StringBuilder(signature);
  221.         for (final Attribute attribute : super.getAttributes()) {
  222.             if (!(attribute instanceof Code || attribute instanceof ExceptionTable)) {
  223.                 buf.append(" [").append(attribute).append("]");
  224.             }
  225.         }
  226.         final ExceptionTable e = getExceptionTable();
  227.         if (e != null) {
  228.             final String str = e.toString();
  229.             if (!str.isEmpty()) {
  230.                 buf.append("\n\t\tthrows ").append(str);
  231.             }
  232.         }
  233.         return buf.toString();
  234.     }
  235. }