Method.java
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.bcel.classfile;
import java.io.DataInput;
import java.io.IOException;
import java.util.Objects;
import org.apache.bcel.generic.Type;
import org.apache.bcel.util.BCELComparator;
/**
* This class represents the method info structure, i.e., the representation for a method in the class. See JVM
* specification for details. A method has access flags, a name, a signature and a number of attributes.
*/
public final class Method extends FieldOrMethod {
/**
* Empty array constant.
*
* @since 6.6.0
*/
public static final Method[] EMPTY_ARRAY = {};
private static BCELComparator<Method> bcelComparator = new BCELComparator<Method>() {
@Override
public boolean equals(final Method a, final Method b) {
return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature());
}
@Override
public int hashCode(final Method o) {
return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0;
}
};
/**
* @return Comparison strategy object.
*/
public static BCELComparator<Method> getComparator() {
return bcelComparator;
}
/**
* @param comparator Comparison strategy object.
*/
public static void setComparator(final BCELComparator<Method> comparator) {
bcelComparator = comparator;
}
/** Annotations defined on the parameters of a method. */
private ParameterAnnotationEntry[] parameterAnnotationEntries;
/**
* Empty constructor, all attributes have to be defined via 'setXXX' methods. Use at your own risk.
*/
public Method() {
}
/**
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
Method(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException {
super(file, constantPool);
}
/**
* @param accessFlags Access rights of method
* @param nameIndex Points to field name in constant pool
* @param signatureIndex Points to encoded signature
* @param attributes Collection of attributes
* @param constantPool Array of constants
*/
public Method(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) {
super(accessFlags, nameIndex, signatureIndex, attributes, constantPool);
}
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
* physical copy.
*
* @param c Source to copy.
*/
public Method(final Method c) {
super(c);
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitMethod(this);
}
/**
* @return deep copy of this method
*/
public Method copy(final ConstantPool constantPool) {
return (Method) copy_(constantPool);
}
/**
* Return value as defined by given BCELComparator strategy. By default two method objects are said to be equal when
* their names and signatures are equal.
*
* @see Object#equals(Object)
*/
@Override
public boolean equals(final Object obj) {
return obj instanceof Method && bcelComparator.equals(this, (Method) obj);
}
/**
* @return array of method argument types
*/
public Type[] getArgumentTypes() {
return Type.getArgumentTypes(getSignature());
}
/**
* @return Code attribute of method, if any
*/
public Code getCode() {
for (final Attribute attribute : super.getAttributes()) {
if (attribute instanceof Code) {
return (Code) attribute;
}
}
return null;
}
/**
* @return ExceptionTable attribute of method, if any, i.e., list all exceptions the method may throw not exception
* handlers!
*/
public ExceptionTable getExceptionTable() {
for (final Attribute attribute : super.getAttributes()) {
if (attribute instanceof ExceptionTable) {
return (ExceptionTable) attribute;
}
}
return null;
}
/**
* @return LineNumberTable of code attribute if any, i.e. the call is forwarded to the Code atribute.
*/
public LineNumberTable getLineNumberTable() {
final Code code = getCode();
if (code == null) {
return null;
}
return code.getLineNumberTable();
}
/**
* @return LocalVariableTable of code attribute if any, i.e. the call is forwarded to the Code attribute.
*/
public LocalVariableTable getLocalVariableTable() {
final Code code = getCode();
if (code == null) {
return null;
}
return code.getLocalVariableTable();
}
/**
* Gets the local variable type table attribute {@link LocalVariableTypeTable}.
* @return LocalVariableTypeTable of code attribute if any, i.e. the call is forwarded to the Code attribute.
* @since 6.10.0
*/
public LocalVariableTypeTable getLocalVariableTypeTable() {
final Code code = getCode();
if (code == null) {
return null;
}
return code.getLocalVariableTypeTable();
}
/**
* @return Annotations on the parameters of a method
* @since 6.0
*/
public ParameterAnnotationEntry[] getParameterAnnotationEntries() {
if (parameterAnnotationEntries == null) {
parameterAnnotationEntries = ParameterAnnotationEntry.createParameterAnnotationEntries(getAttributes());
}
return parameterAnnotationEntries;
}
/**
* @return return type of method
*/
public Type getReturnType() {
return Type.getReturnType(getSignature());
}
/**
* Return value as defined by given BCELComparator strategy. By default return the hash code of the method's name XOR
* signature.
*
* @see Object#hashCode()
*/
@Override
public int hashCode() {
return bcelComparator.hashCode(this);
}
/**
* Return string representation close to declaration format, 'public static void main(String[] args) throws
* IOException', e.g.
*
* @return String representation of the method.
*/
@Override
public String toString() {
final String access = Utility.accessToString(super.getAccessFlags());
// Get name and signature from constant pool
ConstantUtf8 c = super.getConstantPool().getConstantUtf8(super.getSignatureIndex());
String signature = c.getBytes();
c = super.getConstantPool().getConstantUtf8(super.getNameIndex());
final String name = c.getBytes();
signature = Utility.methodSignatureToString(signature, name, access, true, getLocalVariableTable());
final StringBuilder buf = new StringBuilder(signature);
for (final Attribute attribute : super.getAttributes()) {
if (!(attribute instanceof Code || attribute instanceof ExceptionTable)) {
buf.append(" [").append(attribute).append("]");
}
}
final ExceptionTable e = getExceptionTable();
if (e != null) {
final String str = e.toString();
if (!str.isEmpty()) {
buf.append("\n\t\tthrows ").append(str);
}
}
return buf.toString();
}
}