asmlib.InfoClass.java Source code

Java tutorial

Introduction

Here is the source code for asmlib.InfoClass.java

Source

/*
 * asmlib: a toolkit based on ASM for working with java bytecode
 * Copyright (C) 2015 Ivo Anjo <ivo.anjo@ist.utl.pt>
 *
 * This file is part of asmlib.
 *
 * asmlib is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * asmlib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with asmlib.  If not, see <http://www.gnu.org/licenses/>.
 */

package asmlib;

import org.objectweb.asm.Opcodes;

import java.io.IOException;
import java.util.*;

public class InfoClass implements Comparable<InfoClass> {

    private final Type _type;
    private final Type _superclassType;
    private final List<Type> _annotations = new ArrayList<Type>();
    private final List<InfoField> _fields = new ArrayList<InfoField>();
    private final List<InfoMethod> _methods = new ArrayList<InfoMethod>();
    private List<InfoMethod> _superMethods = null;
    private final List<Type> _interfaceTypes = new ArrayList<Type>();
    private final List<InfoClass> _interfaces = new ArrayList<InfoClass>();
    private final List<InfoClass> _subclasses = new ArrayList<InfoClass>();
    private InfoClass _superclass;
    private int _access = -1;

    public InfoClass(Type type, Type superclassType) {
        _type = type;
        _superclassType = superclassType;
    }

    // Auxiliary constructor to avoid clients having to test that superclass != null
    public InfoClass(String classStr, String superclassStr) {
        this(Type.fromAsm(classStr), ((superclassStr != null) ? Type.fromAsm(superclassStr) : null));
    }

    public Type type() {
        return _type;
    }

    public Type superclassType() {
        return _superclassType;
    }

    public InfoClass superclass() {
        return _superclass;
    }

    public void setSuperclass(InfoClass superclass) {
        _superclass = superclass;
        _superclass.addSubclass(this);
    }

    public void addAnnotation(Type annot) {
        _annotations.add(annot);
    }

    public List<Type> annotations() {
        return new ArrayList<Type>(_annotations);
    }

    public void addInterfaceType(Type iface) {
        _interfaceTypes.add(iface);
    }

    public void addInterface(InfoClass iface) {
        if (!_interfaceTypes.contains(iface.type())) {
            throw new InstrumentationException(
                    "Attempt to add an interface which is not on the interfaceTypes() list");
        }

        _interfaces.add(iface);
        iface.addSubclass(this);
    }

    public void setAccess(int access) {
        if (_access < 0)
            _access = access;
        else
            throw new InstrumentationException("Cannot change access after setting it the first time");
    }

    public int access() {
        if (_access < 0)
            throw new InstrumentationException("Access value not set yet");
        return _access;
    }

    public boolean isFinal() {
        return (access() & Opcodes.ACC_FINAL) != 0;
    }

    public boolean isInterface() {
        return (access() & Opcodes.ACC_INTERFACE) != 0;
    }

    public void addField(InfoField field) {
        _fields.add(field);
    }

    public List<InfoField> fields() {
        return new ArrayList<InfoField>(_fields);
    }

    public boolean existsField(String fieldName) {
        for (InfoField f : fields()) {
            if (f.name().equals(fieldName))
                return true;
        }
        return false;
    }

    public void addMethod(InfoMethod method) {
        _methods.add(method);
    }

    public List<InfoMethod> methods() {
        return new ArrayList<InfoMethod>(_methods);
    }

    public List<Type> interfaceTypes() {
        return new ArrayList<Type>(_interfaceTypes);
    }

    public List<InfoClass> interfaces() {
        return new ArrayList<InfoClass>(_interfaces);
    }

    public List<InfoMethod> allMethods() {
        List<InfoMethod> methods = methods();
        if (_superMethods == null) {
            _superMethods = new ArrayList<InfoMethod>();
            if (_superclass != null) {
                for (InfoMethod m : _superclass.allMethods())
                    _superMethods.add(new InfoMethod(m, this));
            }
            for (InfoClass iface : _interfaces) {
                for (InfoMethod m : iface.allMethods())
                    _superMethods.add(new InfoMethod(m, this));
            }
        }
        methods.addAll(_superMethods);
        return methods;
    }

    public InfoMethod getMethod(String methodName, String desc) {
        for (InfoMethod m : methods()) {
            if (m.name().equals(methodName) && m.desc().equals(desc))
                return m;
        }
        return null;
    }

    public InfoMethod getAllMethod(String methodName, String desc) {
        for (InfoMethod m : allMethods()) {
            if (m.name().equals(methodName) && m.desc().equals(desc))
                return m;
        }
        return null;
    }

    public InfoField getField(String fieldName, Type desc) {
        for (InfoField f : fields()) {
            if (f.name().equals(fieldName) && f.desc().equals(desc))
                return f;
        }
        return null;
    }

    public InfoField getAllField(String fieldName, Type desc) {
        InfoField f = getField(fieldName, desc);
        if (f != null)
            return f;

        // The order used in the VM to find fields is current class -> interfaces -> superclasses;
        // This is important whenever fields are being overridden
        for (InfoClass iface : _interfaces) {
            f = iface.getAllField(fieldName, desc);
            if (f != null)
                return f;
        }

        if (_superclass != null)
            return _superclass.getAllField(fieldName, desc);
        return null;
    }

    @Override
    public String toString() {
        return "InfoClass [name=" + type() + /*";annotations=" + annotations() +*/ "]";
    }

    /** Tests if class has an annotation of the given annotation type **/
    public boolean hasAnnotation(Type annot) {
        return _annotations.contains(annot);
    }

    /** Tests if class implements the given inferface type **/
    public boolean hasInterfaceType(Type iface) {
        return _interfaceTypes.contains(iface);
    }

    public void addSubclass(InfoClass subclass) {
        _subclasses.add(subclass);
    }

    public List<InfoClass> subclasses() {
        return new ArrayList<InfoClass>(_subclasses);
    }

    @Override
    public int hashCode() {
        return type().hashCode();
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof InfoClass) {
            InfoClass other = (InfoClass) o;
            return compareTo(other) == 0;
        }
        return false;
    }

    public int compareTo(InfoClass other) {
        return type().compareTo(other.type());
    }

    public static InfoClass fromType(Type t) throws IOException {
        org.objectweb.asm.ClassReader cr = new org.objectweb.asm.ClassReader(t.commonName());
        InfoClass infoClass = new InfoClass(cr.getClassName(), cr.getSuperName());
        cr.accept(new InfoClassAdapter(infoClass), 0);
        return infoClass;
    }

}