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

scouter.javassist.bytecode.annotation.Annotation Maven / Gradle / Ivy

There is a newer version: 2.20.0
Show newest version
/*
 * Javassist, a Java-bytecode translator toolkit.
 * Copyright (C) 2004 Bill Burke. All Rights Reserved.
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License.  Alternatively, the contents of this file may be used under
 * the terms of the GNU Lesser General Public License Version 2.1 or later,
 * or the Apache License Version 2.0.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 */

package scouter.javassist.bytecode.annotation;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import scouter.javassist.ClassPool;
import scouter.javassist.CtClass;
import scouter.javassist.CtMethod;
import scouter.javassist.NotFoundException;
import scouter.javassist.bytecode.ConstPool;
import scouter.javassist.bytecode.Descriptor;

/**
 * The annotation structure.
 *
 * 

An instance of this class is returned by * getAnnotations() in AnnotationsAttribute * or in ParameterAnnotationsAttribute. * * @see scouter.javassist.bytecode.AnnotationsAttribute#getAnnotations() * @see scouter.javassist.bytecode.ParameterAnnotationsAttribute#getAnnotations() * @see MemberValue * @see MemberValueVisitor * @see AnnotationsWriter * * @author Bill Burke * @author Shigeru Chiba * @author Adrian Brock */ public class Annotation { static class Pair { int name; MemberValue value; } ConstPool pool; int typeIndex; Map 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 fully-qualified 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 (CtMethod m:methods) addMemberValue(m.getName(), createMemberValue(cp, m.getReturnType())); } /** * 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("("); for (String name:members.keySet()) { buf.append(name).append("=") .append(getMemberValue(name)) .append(", "); } buf.setLength(buf.length()-2); 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 null; 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 scouter.javassist.bytecode.AnnotationDefaultAttribute */ public MemberValue getMemberValue(String name) { if (members == null||members.get(name) == null) return null; return members.get(name).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 { Class clazz = MemberValue.loadClass(cl, getTypeName()); try { return AnnotationImpl.make(cl, clazz, cp, this); } catch (IllegalArgumentException e) { /* AnnotationImpl.make() may throw this exception * when it fails to make a proxy object for some * reason. */ throw new ClassNotFoundException(clazz.getName(), e); } catch (IllegalAccessError e2) { // also IllegalAccessError throw new ClassNotFoundException(clazz.getName(), e2); } } /** * 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()); for (Pair pair:members.values()) { writer.memberValuePair(pair.name); pair.value.write(writer); } } @Override public int hashCode() { return getTypeName().hashCode() + (members == null ? 0 : members.hashCode()); } /** * 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; Map 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 - 2024 Weber Informatics LLC | Privacy Policy