    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 *  Unless required by applicable law or agreed to in writing, software
    012 *  distributed under the License is distributed on an "AS IS" BASIS,
    013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 *  See the License for the specific language governing permissions and
    015 *  limitations under the License.
    016 *
    017 */
    018package org.apache.bcel.classfile;
    019
    020import java.io.DataInput;
    021import java.io.IOException;
    022import java.util.Objects;
    023
    024import org.apache.bcel.Const;
    025import org.apache.bcel.generic.Type;
    026import org.apache.bcel.util.BCELComparator;
    027
    028/**
    029 * This class represents the method info structure, i.e., the representation
    030 * for a method in the class. See JVM specification for details.
    031 * A method has access flags, a name, a signature and a number of attributes.
    032 *
    033 * @version $Id$
    034 */
    035public final class Method extends FieldOrMethod {
    036
    037    private static BCELComparator bcelComparator = new BCELComparator() {
    038
    039        @Override
    040        public boolean equals( final Object o1, final Object o2 ) {
    041            final Method THIS = (Method) o1;
    042            final Method THAT = (Method) o2;
    043            return Objects.equals(THIS.getName(), THAT.getName())
    044                    && Objects.equals(THIS.getSignature(), THAT.getSignature());
    045        }
    046
    047
    048        @Override
    049        public int hashCode( final Object o ) {
    050            final Method THIS = (Method) o;
    051            return THIS.getSignature().hashCode() ^ THIS.getName().hashCode();
    052        }
    053    };
    054
    055    // annotations defined on the parameters of a method
    056    private ParameterAnnotationEntry[] parameterAnnotationEntries;
    057
    058    /**
    059     * Empty constructor, all attributes have to be defined via `setXXX'
    060     * methods. Use at your own risk.
    061     */
    062    public Method() {
    063    }
    064
    065
    066    /**
    067     * Initialize from another object. Note that both objects use the same
    068     * references (shallow copy). Use clone() for a physical copy.
    069     */
    070    public Method(final Method c) {
    071        super(c);
    072    }
    073
    074
    075    /**
    076     * Construct object from file stream.
    077     * @param file Input stream
    078     * @throws IOException
    079     * @throws ClassFormatException
    080     */
    081    Method(final DataInput file, final ConstantPool constant_pool) throws IOException,
    082            ClassFormatException {
    083        super(file, constant_pool);
    084    }
    085
    086
    087    /**
    088     * @param access_flags Access rights of method
    089     * @param name_index Points to field name in constant pool
    090     * @param signature_index Points to encoded signature
    091     * @param attributes Collection of attributes
    092     * @param constant_pool Array of constants
    093     */
    094    public Method(final int access_flags, final int name_index, final int signature_index, final Attribute[] attributes,
    095            final ConstantPool constant_pool) {
    096        super(access_flags, name_index, signature_index, attributes, constant_pool);
    097    }
    098
    099
    100    /**
    101     * Called by objects that are traversing the nodes of the tree implicitely
    102     * defined by the contents of a Java class. I.e., the hierarchy of methods,
    103     * fields, attributes, etc. spawns a tree of objects.
    104     *
    105     * @param v Visitor object
    106     */
    107    @Override
    108    public void accept( final Visitor v ) {
    109        v.visitMethod(this);
    110    }
    111
    112
    113    /**
    114     * @return Code attribute of method, if any
    115     */
    116    public final Code getCode() {
    117        for (final Attribute attribute : super.getAttributes()) {
    118            if (attribute instanceof Code) {
    119                return (Code) attribute;
    120            }
    121        }
    122        return null;
    123    }
    124
    125
    126    /**
    127     * @return ExceptionTable attribute of method, if any, i.e., list all
    128     * exceptions the method may throw not exception handlers!
    129     */
    130    public final ExceptionTable getExceptionTable() {
    131        for (final Attribute attribute : super.getAttributes()) {
    132            if (attribute instanceof ExceptionTable) {
    133                return (ExceptionTable) attribute;
    134            }
    135        }
    136        return null;
    137    }
    138
    139
    140    /** @return LocalVariableTable of code attribute if any, i.e. the call is forwarded
    141     * to the Code atribute.
    142     */
    143    public final LocalVariableTable getLocalVariableTable() {
    144        final Code code = getCode();
    145        if (code == null) {
    146            return null;
    147        }
    148        return code.getLocalVariableTable();
    149    }
    150
    151
    152    /** @return LineNumberTable of code attribute if any, i.e. the call is forwarded
    153     * to the Code atribute.
    154     */
    155    public final LineNumberTable getLineNumberTable() {
    156        final Code code = getCode();
    157        if (code == null) {
    158            return null;
    159        }
    160        return code.getLineNumberTable();
    161    }
    162
    163
    164    /**
    165     * Return string representation close to declaration format,
    166     * `public static void main(String[] args) throws IOException', e.g.
    167     *
    168     * @return String representation of the method.
    169     */
    170    @Override
    171    public final String toString() {
    172        final String access = Utility.accessToString(super.getAccessFlags());
    173        // Get name and signature from constant pool
    174        ConstantUtf8 c = (ConstantUtf8) super.getConstantPool().getConstant(super.getSignatureIndex(), Const.CONSTANT_Utf8);
    175        String signature = c.getBytes();
    176        c = (ConstantUtf8) super.getConstantPool().getConstant(super.getNameIndex(), Const.CONSTANT_Utf8);
    177        final String name = c.getBytes();
    178        signature = Utility.methodSignatureToString(signature, name, access, true,
    179                getLocalVariableTable());
    180        final StringBuilder buf = new StringBuilder(signature);
    181        for (final Attribute attribute : super.getAttributes()) {
    182            if (!((attribute instanceof Code) || (attribute instanceof ExceptionTable))) {
    183                buf.append(" [").append(attribute).append("]");
    184            }
    185        }
    186        final ExceptionTable e = getExceptionTable();
    187        if (e != null) {
    188            final String str = e.toString();
    189            if (!str.isEmpty()) {
    190                buf.append("\n\t\tthrows ").append(str);
    191            }
    192        }
    193        return buf.toString();
    194    }
    195
    196
    197    /**
    198     * @return deep copy of this method
    199     */
    200    public final Method copy( final ConstantPool _constant_pool ) {
    201        return (Method) copy_(_constant_pool);
    202    }
    203
    204
    205    /**
    206     * @return return type of method
    207     */
    208    public Type getReturnType() {
    209        return Type.getReturnType(getSignature());
    210    }
    211
    212
    213    /**
    214     * @return array of method argument types
    215     */
    216    public Type[] getArgumentTypes() {
    217        return Type.getArgumentTypes(getSignature());
    218    }
    219
    220
    221    /**
    222     * @return Comparison strategy object
    223     */
    224    public static BCELComparator getComparator() {
    225        return bcelComparator;
    226    }
    227
    228
    229    /**
    230     * @param comparator Comparison strategy object
    231     */
    232    public static void setComparator( final BCELComparator comparator ) {
    233        bcelComparator = comparator;
    234    }
    235
    236
    237    /**
    238     * Return value as defined by given BCELComparator strategy.
    239     * By default two method objects are said to be equal when
    240     * their names and signatures are equal.
    241     *
    242     * @see java.lang.Object#equals(java.lang.Object)
    243     */
    244    @Override
    245    public boolean equals( final Object obj ) {
    246        return bcelComparator.equals(this, obj);
    247    }
    248
    249
    250    /**
    251     * Return value as defined by given BCELComparator strategy.
    252     * By default return the hashcode of the method's name XOR signature.
    253     *
    254     * @see java.lang.Object#hashCode()
    255     */
    256    @Override
    257    public int hashCode() {
    258        return bcelComparator.hashCode(this);
    259    }
    260
    261    /**
    262     * @return Annotations on the parameters of a method
    263     * @since 6.0
    264     */
    265    public ParameterAnnotationEntry[] getParameterAnnotationEntries() {
    266        if (parameterAnnotationEntries == null) {
    267            parameterAnnotationEntries = ParameterAnnotationEntry.createParameterAnnotationEntries(getAttributes());
    268        }
    269        return parameterAnnotationEntries;
    270    }
    271}