All Downloads are FREE. Search and download functionalities are using the official Maven repository.

xapi.bytecode.Annotation Maven / Gradle / Ivy

package xapi.bytecode;

import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Set;


public class Annotation {
    static class Pair {
        int name;
        MemberValue value;
    }

    ConstPool pool;
    int typeIndex;
    LinkedHashMap members;    // this sould be LinkedHashMap
                        // but it is not supported by JDK 1.3.

    /**
     * Constructs an annotation including no members.  A member can be
     * later added to the created annotation by addMemberValue().
     *
     * @param type  the index into the constant pool table.
     *              the entry at that index must be the
     *              CONSTANT_Utf8_Info structure
     *              repreenting the name of the annotation interface type.
     * @param cp    the constant pool table.
     *
     * @see #addMemberValue(String, MemberValue)
     */
    public Annotation(int type, ConstPool cp) {
        pool = cp;
        typeIndex = type;
        members = null;
    }

    /**
     * Constructs an annotation including no members.  A member can be
     * later added to the created annotation by addMemberValue().
     *
     * @param typeName  the name of the annotation interface type.
     * @param cp        the constant pool table.
     *
     * @see #addMemberValue(String, MemberValue)
     */
    public Annotation(String typeName, ConstPool cp) {
        this(cp.addUtf8Info(Descriptor.of(typeName)), cp);
    }

    /**
     * Constructs an annotation that can be accessed through the interface
     * represented by clazz.  The values of the members are
     * not specified.
     *
     * @param cp        the constant pool table.
     * @param clazz     the interface.
     * @throws NotFoundException when the clazz is not found
     */
    public Annotation(ConstPool cp, CtClass clazz)
        throws NotFoundException
    {
        // todo Enums are not supported right now.
        this(cp.addUtf8Info(Descriptor.of(clazz.getName())), cp);

        if (!clazz.isInterface())
            throw new RuntimeException(
                "Only interfaces are allowed for Annotation creation.");

        CtMethod methods[] = clazz.getDeclaredMethods();
        if (methods.length > 0) {
            members = new LinkedHashMap();
        }

        for (int i = 0; i < methods.length; i++) {
            CtClass returnType = methods[i].getReturnType();
            addMemberValue(methods[i].getName(),
                           createMemberValue(cp, returnType));

        }
    }

    /**
     * Makes an instance of MemberValue.
     *
     * @param cp            the constant pool table.
     * @param type          the type of the member.
     * @return the member value
     * @throws NotFoundException when the type is not found
     */
    public static MemberValue createMemberValue(ConstPool cp, CtClass type)
        throws NotFoundException
    {
        if (type == CtClass.booleanType)
            return new BooleanMemberValue(cp);
        else if (type == CtClass.byteType)
            return new ByteMemberValue(cp);
        else if (type == CtClass.charType)
            return new CharMemberValue(cp);
        else if (type == CtClass.shortType)
            return new ShortMemberValue(cp);
        else if (type == CtClass.intType)
            return new IntegerMemberValue(cp);
        else if (type == CtClass.longType)
            return new LongMemberValue(cp);
        else if (type == CtClass.floatType)
            return new FloatMemberValue(cp);
        else if (type == CtClass.doubleType)
            return new DoubleMemberValue(cp);
        else if (type.getName().equals("java.lang.Class"))
            return new ClassMemberValue(cp);
        else if (type.getName().equals("java.lang.String"))
            return new StringMemberValue(cp);
        else if (type.isArray()) {
            CtClass arrayType = type.getComponentType();
            MemberValue member = createMemberValue(cp, arrayType);
            return new ArrayMemberValue(member, cp);
        }
        else if (type.isInterface()) {
            Annotation info = new Annotation(cp, type);
            return new AnnotationMemberValue(info, cp);
        }
        else {
            // treat as enum.  I know this is not typed,
            // but JBoss has an Annotation Compiler for JDK 1.4
            // and I want it to work with that. - Bill Burke
            EnumMemberValue emv = new EnumMemberValue(cp);
            emv.setType(type.getName());
            return emv;
        }
    }

    /**
     * Adds a new member.
     *
     * @param nameIndex     the index into the constant pool table.
     *                      The entry at that index must be
     *                      a CONSTANT_Utf8_info structure.
     *                      structure representing the member name.
     * @param value         the member value.
     */
    public void addMemberValue(int nameIndex, MemberValue value) {
        Pair p = new Pair();
        p.name = nameIndex;
        p.value = value;
        addMemberValue(p);
    }

    /**
     * Adds a new member.
     *
     * @param name      the member name.
     * @param value     the member value.
     */
    public void addMemberValue(String name, MemberValue value) {
        Pair p = new Pair();
        p.name = pool.addUtf8Info(name);
        p.value = value;
        if (members == null)
            members = new LinkedHashMap();

        members.put(name, p);
    }

    private void addMemberValue(Pair pair) {
        String name = pool.getUtf8Info(pair.name);
        if (members == null)
            members = new LinkedHashMap();

        members.put(name, pair);
    }

    /**
     * Returns a string representation of the annotation.
     */
    @Override
    public String toString() {
        StringBuffer buf = new StringBuffer("@");
        buf.append(getTypeName());
        if (members != null) {
            buf.append("(");
            Iterator mit = members.keySet().iterator();
            while (mit.hasNext()) {
                String name = (String)mit.next();
                buf.append(name).append("=").append(getMemberValue(name));
                if (mit.hasNext())
                    buf.append(", ");
            }
            buf.append(")");
        }

        return buf.toString();
    }

    /**
     * Obtains the name of the annotation type.
     *
     * @return the type name
     */
    public String getTypeName() {
        return Descriptor.toClassName(pool.getUtf8Info(typeIndex));
    }

    /**
     * Obtains all the member names.
     *
     * @return null if no members are defined.
     */
    public Set getMemberNames() {
        if (members == null)
            return new HashSet();
        else
            return members.keySet();
    }

    /**
     * Obtains the member value with the given name.
     *
     * 

If this annotation does not have a value for the * specified member, * this method returns null. It does not return a * MemberValue with the default value. * The default value can be obtained from the annotation type. * * @param name the member name * @return null if the member cannot be found or if the value is * the default value. * * @see javassist.bytecode.AnnotationDefaultAttribute */ public MemberValue getMemberValue(String name) { if (members == null) return null; else { Pair p = (Pair)members.get(name); if (p == null) return null; else return p.value; } } /** * Constructs an annotation-type object representing this annotation. * For example, if this annotation represents @Author, * this method returns an Author object. * * @param cl class loader for loading an annotation type. * @param cp class pool for obtaining class files. * @return the annotation * @throws ClassNotFoundException if the class cannot found. * @throws NoSuchClassError if the class linkage fails. */ public Object toAnnotationType(ClassLoader cl, ClassPool cp) throws ClassNotFoundException, NoSuchClassError { return AnnotationImpl.make(cl, MemberValue.loadClass(cl, getTypeName()), cp, this); } /** * Writes this annotation. * * @param writer the output. * @throws IOException for an error during the write */ public void write(AnnotationsWriter writer) throws IOException { String typeName = pool.getUtf8Info(typeIndex); if (members == null) { writer.annotation(typeName, 0); return; } writer.annotation(typeName, members.size()); Iterator it = members.values().iterator(); while (it.hasNext()) { Pair pair = (Pair)it.next(); writer.memberValuePair(pair.name); pair.value.write(writer); } } /** * Returns true if the given object represents the same annotation * as this object. The equality test checks the member values. */ @Override public boolean equals(Object obj) { if (obj == this) return true; if (obj == null || obj instanceof Annotation == false) return false; Annotation other = (Annotation) obj; if (getTypeName().equals(other.getTypeName()) == false) return false; LinkedHashMap otherMembers = other.members; if (members == otherMembers) return true; else if (members == null) return otherMembers == null; else if (otherMembers == null) return false; else return members.equals(otherMembers); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy