Package alt.jiapi.reflect

Source Code of alt.jiapi.reflect.JiapiClass

/*
* Copyright (C) 2001 Mika Riekkinen, Joni Suominen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

package alt.jiapi.reflect;

import java.io.IOException;
import java.io.OutputStream;
import java.io.ByteArrayInputStream;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.LinkedList;
import java.util.Map;

import org.apache.log4j.Category;

import alt.jiapi.InstrumentationContext;
import alt.jiapi.JiapiException;
import alt.jiapi.Runtime;

import alt.jiapi.file.Attribute;
import alt.jiapi.file.ClassFile;
import alt.jiapi.file.ConstantPool;
import alt.jiapi.file.Field;
import alt.jiapi.file.Interface;
import alt.jiapi.file.Method;

/**
* This class represents a bytecode of a Class.
* It contains methods to add and remove <code>JiapiMethod</code>s and
* <code>JiapiField</code>s.
* <p>
* JiapiClass is an abstract class. Concrete classes are loaded
* using Loader.
* <blockquote>
* <code>
* Loader loader = new Loader();
* JiapiClass clazz = loader.loadClass(className);
* </code>
* </blockquote>
*
* @author Mika Riekkinen
* @author Joni Suominen
* @version $Revision: 1.30 $ $Date: 2005/05/24 12:10:26 $
* @see Loader
*/
public class JiapiClass {
    // Used in Collection.toArray(fieldArrayTemplate)
    private static final JiapiField[] fieldArrayTemplate = new JiapiField[0];
    private static final JiapiMethod[] methodArrayTemplate =new JiapiMethod[0];

    private static Category log = Runtime.getLogCategory(JiapiClass.class);

    private Loader loader; // Loader that loaded this JiapiClass
    private ClassBuilder builder;
    private ClassFile clazz;

    private List jiapiMethods;
    private List jiapiFields;

    // Used for testing
    public static void main(String[] args) throws Exception {
        Loader l = new Loader();
        JiapiClass jc = l.loadClass(args[0]);
        System.out.println(jc);
    }


    /**
     * Create empty JiapiClass.
     * Created JiapiClass has all internal datastructures initialized so,
     * that when dumped to byte[], it is a valid java class file.
     * It has not methods, fields etc.
     *
     * @param name Name of the JiapiClass to create
     * @return an instance of JiapiClass
     */
    public static JiapiClass createClass(String name) {
        ClassFile cf = new ClassFile(name);
        return new JiapiClass(cf);
    }


    /**
     * Parses byte[] for a class definition.
     */
    public static JiapiClass parseClass(byte[] bytes) throws IOException {
  ByteArrayInputStream bais = new ByteArrayInputStream(bytes);

        ClassFile cf = ClassFile.parse(bais);
        return new JiapiClass(cf);
    }


    private JiapiClass() {
    }


    JiapiClass(ClassFile classFile) {
        this.clazz = classFile;
        this.builder = new ClassBuilder(classFile);
  this.loader = new Loader();

        jiapiMethods = new LinkedList();
        jiapiFields = new LinkedList();

        List methods = clazz.getMethods();
        Iterator i = methods.iterator();
        while(i.hasNext()) {
            Method m = (Method)i.next();

            JiapiMethod jm = new JiapiMethod(m);
            jm.setDeclaringClass(this);

            jiapiMethods.add(jm);
        }


        List fields = clazz.getFields();
        i = fields.iterator();
        while(i.hasNext()) {
            Field f = (Field)i.next();

            JiapiField jf = new JiapiField(f);
            jf.setDeclaringClass(this);

            jiapiFields.add(jf);
        }
    }


    /**
     * Dumps bytecodes of this JiapiClass to OutputStream given.
     * @param out OutputStream to use
     */
    public void dump(OutputStream out) throws IOException {
        out.write(getByteCode());
    }

   
    /**
     * Gets the Loader, that loaded this JiapiClass.
     *
     * @return Loader
     */
    public Loader getLoader() {
        return loader;
    }


    /**
     * Get name of a class.
     *
     * @return name of a class
     */
    public String getName() {
        return clazz.getClassName();
    }

    /**
     * Get the package where this class is defined.
     *
     * @return a package name of a class, or null if this class does
     *         not belong to any package.
     */
    public String getPackageName() {
        String cName = getName();
        int idx = cName.lastIndexOf('.'); // NOTE: InnerClasses ???
        if (idx == -1) {
            return null;
        }

        return cName.substring(0, idx);
    }

    /**
     * Get the byte-code of this class.
     *
     * @return an array of bytecodes
     */
    public byte[] getByteCode() {
        // Loop methods for changed bytecode
        JiapiMethod[] methods = getDeclaredMethods();
        for(int i = 0; i < methods.length; i++) {
            methods[i].update();
        }

        return clazz.toBytes();
    }


    /**
     * Get all the methods of this JiapiClass and its superclasses.
     *
     * @return an array of methods in this class
     * @see #getDeclaredMethods() getDeclaredMethods() for further info
     * @exception ClassNotFoundException is thrown if superclass could
     *            not be loaded
     */
    public JiapiMethod[] getMethods() throws ClassNotFoundException {
        ArrayList al = new ArrayList();
        JiapiClass jc = this;

        do {
            al.addAll(jc.jiapiMethods);
        }
        while((jc = jc.getSuperclass()) != null);

        return (JiapiMethod[])al.toArray(methodArrayTemplate);
    }

    /**
     * Get all the methods of this JiapiClass. If this JiapiClass
     * has no methods, an array of length 0 is returned. A new array is created
     * each time this method is called, so adding and removing items from array
     * does not reflect such changes back into JiapiClass.
     *
     * @return an array of methods in this class
     */
    public JiapiMethod[] getDeclaredMethods() {
        ArrayList al = new ArrayList();
        al.addAll(jiapiMethods);

        return (JiapiMethod[])al.toArray(methodArrayTemplate);
    }


    /**
     * Get a specific method from a class. Parameter type names are given
     * in simple form. This would be the same as used when programming java
     * code. Some examples of simple form: <code>java.lang.Object</code>,
     * <code>int</code>, <code>int[]</code>, <code>my.stuff.Thing[]</code><p>
     * Example:
     * <pre>
     *   JiapiClass clazz = ...;
     *   String[] paramTypeNames = new String[] {"java.lang.Object[]", "int"};
     *   JiapiMethod m = clazz.getMethod("foo", paramTypeNames);
     * </pre>
     * Would return a method <code>foo(Object[], int)</code>
     *
     * @param name Name of the method
     * @param parameterTypeNames Type names of the parameters
     * @return a method which matches the given name and parameter types
     * @exception NoSuchMethodException if matching method is not found
     */
    public JiapiMethod getDeclaredMethod(String name,
                                         String[] parameterTypeNames) throws NoSuchMethodException {
        Signature otherSignature = new Signature("void", parameterTypeNames);

        Iterator i = jiapiMethods.iterator();
        while (i.hasNext()) {
            JiapiMethod jm = (JiapiMethod)i.next();
            if (jm.getName().equals(name)) {
                if (jm.getSignature().equals(otherSignature)) {
                    return jm;
                }
            }
        }

        throw new NoSuchMethodException(name + otherSignature.toString());
    }

    /**
     * Get a specific method from a class.
     *
     * @param parameterTypes An array of JiapiClass, where each element
     *        represents a parameter.
     * @return a method which matches the given name and parameter types
     * @exception NoSuchMethodException if matching method is not found
     */
    public JiapiMethod getDeclaredMethod(String name,
                                         JiapiClass[] parameterTypes)
            throws NoSuchMethodException {

        String[] parameterTypeNames = null;
        if (parameterTypes != null) {
            parameterTypeNames = new String[parameterTypes.length];
            for (int i = 0; i < parameterTypes.length; i++) {
                parameterTypeNames[i] = parameterTypes[i].getName();
            }
        }

        return getDeclaredMethod(name, parameterTypeNames);
    }


    /**
     * Get a specific method from a class or any of its superclasses.
     * Parameter type names are given in simple form. This would be the
     * same as used when programming java
     * code. Some examples of simple form: <code>java.lang.Object</code>,
     * <code>int</code>, <code>int[]</code>, <code>my.stuff.Thing[]</code><p>
     * Example:
     * <pre>
     *   JiapiClass clazz = ...;
     *   String[] paramTypeNames = new String[] {"java.lang.Object[]", "int"};
     *   JiapiMethod m = clazz.getMethod("foo", paramTypeNames);
     * </pre>
     * Would return a method <code>foo(Object[], int)</code>
     *
     * @param name Name of the method
     * @param parameterTypeNames Type names of the parameters
     * @return a method which matches the given name and parameter types
     * @exception NoSuchMethodException if matching method is not found
     * @exception ClassNotFoundException is thrown if superclass could
     *                                   not be loaded
     */
    public JiapiMethod getMethod(String name, String[] parameterTypeNames)
            throws NoSuchMethodException, ClassNotFoundException {
        JiapiClass jc = this;
        JiapiMethod method = null;

        do {
            try {
                method = jc.getDeclaredMethod(name, parameterTypeNames);
                return method;
            } catch (NoSuchMethodException nsme) {
                // Don't mind.
            }
        }
        while ((jc = jc.getSuperclass()) != null);

        throw new NoSuchMethodException(name);
    }

    /**
     * Get a specific method from a class or any of its superclasses.
     *
     * @param parameterTypes An array of JiapiClass, where each element
     *        represents a parameter.
     * @return a method which matches the given name and parameter types
     * @exception NoSuchMethodException if matching method is not found
     * @exception ClassNotFoundException is thrown if superclass could
     *                                   not be loaded
     */
    public JiapiMethod getMethod(String name, JiapiClass[] parameterTypes)
            throws NoSuchMethodException, ClassNotFoundException {
        JiapiClass jc = this;
        JiapiMethod method = null;

        do {
            try {
                method = jc.getDeclaredMethod(name, parameterTypes);
                return method;
            } catch (NoSuchMethodException nsme) {
                // Don't mind.
            }
        }
        while ((jc = jc.getSuperclass()) != null);

        throw new NoSuchMethodException(name);
    }


    /**
     * Get all the Fields of this JiapiClass and its superclasses.
     * All of the fields in this class and superclasses are returned.
     *
     * @return an array of fields in this class and its superclasses
     * @see #getDeclaredFields getDeclaredFields() for further info
     * @exception ClassNotFoundException is thrown if superclass could
     *            not be loaded
     */
    public JiapiField[] getFields() throws ClassNotFoundException {
        ArrayList al = new ArrayList();
        JiapiClass jc = this;

        do {
            al.addAll(jc.jiapiFields);
        }
        while ((jc = jc.getSuperclass()) != null);

        return (JiapiField[])al.toArray(fieldArrayTemplate);
    }

    /**
     * Get all the fields declared by this JiapiClass. If this JiapiClass
     * has no fields, an array of length 0 is returned. A new array is created
     * each time this method is called, so adding and removing items from array
     * does not reflect such changes back into JiapiClass.
     *
     * @return an array of fields in this class
     */
    public JiapiField[] getDeclaredFields() {
        ArrayList al = new ArrayList();
        al.addAll(jiapiFields);

        return (JiapiField[])al.toArray(fieldArrayTemplate);
    }

    /**
     * Get a declared field of a class.
     *
     * @param name a name of a field
     * @return a field with a given name
     * @exception NoSuchFieldException if matching field is not found
     */
    public JiapiField getDeclaredField(String name) throws NoSuchFieldException {
        Iterator i = jiapiFields.iterator();
        while(i.hasNext()) {
            JiapiField f = (JiapiField)i.next();
            if (f.getName().equals(name)) {
                return f;
            }
        }

        throw new NoSuchFieldException(name);
    }

    /**
     * Get a field from a class or from any of its superclasses.
     *
     * @param name a name of a field
     * @return a field with a given name
     * @exception NoSuchFieldException if matching field is not found
     * @exception ClassNotFoundException is thrown if superclass could
     *            not be loaded
     */
    public JiapiField getField(String name) throws NoSuchFieldException, ClassNotFoundException {
        JiapiClass jc = this;
        JiapiField field = null;

        do {
            try {
                field = jc.getDeclaredField(name);
                return field;
            } catch (NoSuchFieldException nsfe) {
                // Don't mind.
            }
        }
        while ((jc = jc.getSuperclass()) != null);

        throw new NoSuchFieldException(name);
    }

    /**
     * Gets the super class of this JiapiClass. If this JiapiClass
     * represents java.lang.Object, a null is returned.
     *
     * @return super class of the class represented by this JiapiClass
     * @exception ClassNotFoundException is thrown, if superclass could not
     *            be loaded
     */
    public JiapiClass getSuperclass() throws ClassNotFoundException {
        String scName = clazz.getSuperclassName();
        JiapiClass superClass = null;
        if (scName != null) {
            try {
                superClass = loader.loadClass(scName);
            }
            catch(IOException ioe) {
                log.error("", ioe);
            }
        }

        return superClass;
    }

    /**
     * Get modifiers of this JiapiClass.
     *
     * @return access modifiers of a class
     * @see java.lang.reflect.Modifier
     */
    public int getModifiers() {
        return clazz.getAccessFlags();
    }


    /**
     * Adds a named Field to this JiapiClass. Field will be <code>
     * public</code> and of type <code>java.lang.Object</code>
     *
     * @param name Name of the field to be added
     * @return JiapiField which was added
     * @exception FieldExistsException if a field with a same name already
     *            exists
     */
    public JiapiField addField(String name) throws FieldExistsException {
        return addField((short)Modifier.PUBLIC, "java.lang.Object", name);
    }

    /**
     * Adds a new Field to this JiapiClass.
     *
     * @param modifiers Modifiers of the field
     * @param type Type of the field to be added. Type is given in
     *        simple form, like 'java.lang.Object' or 'int'
     * @param name Name of the field to be added
     * @return JiapiField which was added
     * @exception FieldExistsException if a field with a same name already
     *            exists
     */
    public JiapiField addField(int modifiers, String type, String name) throws FieldExistsException {
        JiapiField jf = builder.addField((short)modifiers, type, name);
        jf.setDeclaringClass(this);
        jiapiFields.add(jf);

        return jf;
    }
   


    /**
     * Gets all the interfaces, that this class directly implements.
     *
     * @return names of the implemented interfaces
     */
    public String[] getInterfaceNames() {
        ConstantPool cp = clazz.getConstantPool();
        List l = clazz.getInterfaces();

        String[] iNames = new String[l.size()];
        for (int i = 0; i < iNames.length; i++) {
            Interface iFace = (Interface)l.get(i);

            iNames[i] = iFace.getName();
        }

        return iNames;
    }

    /**
     * Gets all the interfaces, that this class directly implements.
     *
     * @return names of the implemented interfaces
     */
    public JiapiClass[] getInterfaceTypes() throws ClassNotFoundException {
        String[] iNames = getInterfaceNames();
        JiapiClass[] interfaces = new JiapiClass[iNames.length];

        for (int i = 0; i < interfaces.length; i++) {
            try {
                interfaces[i] = getLoader().loadClass(iNames[i]);
            }
            catch(java.io.IOException ioe) {
                throw new ClassNotFoundException(iNames[i]);
            }
        }

        return interfaces;
    }

    /**
     * Adds an interface for a class.
     * If current class is an interface, it extends the added interface.
     * Otherwise it implements it.
     *
     * @param interfaceType the type of an interface
     */
    public void addInterface(String interfaceType) {
        clazz.addInterface(interfaceType);
    }


    /**
     * Adds an interface for a class.
     * If current class is an interface, it extends the added interface.
     * Otherwise it implements it.
     *
     * @param interfaceType the type of an interface
     * @exception IllegalArgumentException is thrown, if interfaceType is
     *            not an interface.
     */
    public void addInterface(JiapiClass interfaceType) throws IllegalArgumentException {
        if (!interfaceType.isInterface()) {
            throw new IllegalArgumentException("Not an interface: " +
                                               interfaceType.getName());
        }

        addInterface(interfaceType.getName());
    }
   
    /**
     * Adds a new method to this class. The signature is derived
     * from given methods signature.
     *
     * @param m JiapiMethod to be used as method signature
     * @return JiapiMethod which was added
     * @exception MethodExistsException if a method with a same name and
     *            parameter signature already exists
     */
    public JiapiMethod addMethod(JiapiMethod m) throws MethodExistsException {
        return addMethod((int)m.getModifiers(), m.getName(), m.getSignature());
    }

    /**
     * Adds a new method to this class. Method, that is added, do not
     * contain any bytecode. It is the responsibility of the developer
     * to provide later some meaningful method body.
     *
     * @param modifiers access modifiers of a class
     * @param methodName name of a method
     * @param signature signature of a method
     * @return JiapiMethod which was added
     * @exception MethodExistsException if a method with a same name and
     *            parameter signature already exists
     * @see java.lang.reflect.Modifier
     */
    public JiapiMethod addMethod(int modifiers, String methodName,
                                 Signature signature) throws MethodExistsException {
        JiapiMethod jm = null;
        // Check, that the method don't exist
        Iterator i = jiapiMethods.iterator();
        while(i.hasNext()) {
            JiapiMethod method = (JiapiMethod)i.next();
            if (method.getName().equals(methodName) &&
                method.getSignature().getDescriptor().equals(signature.getDescriptor())) {

                throw new MethodExistsException(method);
            }
        }
       


        try {
            jm = builder.addMethod((short)modifiers, methodName, signature);
        }
        catch(MethodExistsException mee) {
            jm = mee.getMethod();
            jm.setDeclaringClass(this);

            throw mee;
        }

        jm.setDeclaringClass(this);
        jiapiMethods.add(jm);

        return jm;
    }


    /**
     * Tests, whether this JiapiClass is an interface or not.
     *
     * @return true, if this JiapiClass represents an interface.
     */
    public boolean isInterface() {
        return Modifier.isInterface(getModifiers());
    }

    public String toString() {
        StringBuffer sb = new StringBuffer();

        // clear ACC_SUPER(0x0020 -> 0xffdf), otherwise 'synchronized' would
        // be returned by java.lang.reflect.Modifier
        sb.append(Modifier.toString(getModifiers() & 0xffdf));
        sb.append(" JiapiClass ");
        sb.append(getName());

        String[] interfaces = getInterfaceNames();
        if (interfaces.length > 0) {
            sb.append(" implements ");
            for (int i = 0; i < interfaces.length; i++) {
                sb.append(interfaces[i]);
                if (i < interfaces.length - 1) {
                    sb.append(", ");
                }
            }
        }

        sb.append("\nFields:");
        JiapiField[] fields = getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            sb.append("\n  ");
            sb.append(fields[i].toString());
        }

        sb.append("\nMethods:");
        JiapiMethod[] methods = getDeclaredMethods();
        for (int i = 0; i < methods.length; i++) {
            sb.append("\n  ");
            sb.append(methods[i].toString());

//             sb.append('\n');
//             sb.append(methods[i].getInstructionList());
        }

        return sb.toString();
    }


    // Package access  -----------------
    void setLoader(Loader l) {
        this.loader = l;
    }


    // Made public for alt.jiapi.tool.Javap
//     public ClassFile getClassFile() {
//         return clazz;
//     }

    /**
     * Get the ConstantPool related to this JiapiClass.
     *
     * @return ConstantPool of this JiapiClass
     */
    public ConstantPool getConstantPool() {
        return clazz.getConstantPool();
    }
}
TOP

Related Classes of alt.jiapi.reflect.JiapiClass

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.