001: /*
002: * Javassist, a Java-bytecode translator toolkit.
003: * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
004: *
005: * The contents of this file are subject to the Mozilla Public License Version
006: * 1.1 (the "License"); you may not use this file except in compliance with
007: * the License. Alternatively, the contents of this file may be used under
008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the
013: * License.
014: */
015:
016: package javassist.bytecode.annotation;
017:
018: import javassist.ClassPool;
019: import javassist.CtClass;
020: import javassist.NotFoundException;
021: import javassist.bytecode.AnnotationDefaultAttribute;
022: import javassist.bytecode.ClassFile;
023: import javassist.bytecode.MethodInfo;
024:
025: import java.lang.reflect.*;
026:
027: /**
028: * Internal-use only. This is a helper class internally used for implementing
029: * <code>toAnnotationType()</code> in <code>Annotation</code>.
030: */
031: public class AnnotationImpl implements InvocationHandler {
032: private Annotation annotation;
033: private ClassPool pool;
034: private ClassLoader classLoader;
035:
036: /**
037: * Constructs an annotation object.
038: *
039: * @param cl class loader for obtaining annotation types.
040: * @param clazz the annotation type.
041: * @param cp class pool for containing an annotation
042: * type (or null).
043: * @param anon the annotation.
044: */
045: public static Object make(ClassLoader cl, Class clazz,
046: ClassPool cp, Annotation anon) {
047: AnnotationImpl handler = new AnnotationImpl(anon, cp, cl);
048: return Proxy.newProxyInstance(cl, new Class[] { clazz },
049: handler);
050: }
051:
052: private AnnotationImpl(Annotation a, ClassPool cp,
053: ClassLoader loader) {
054: annotation = a;
055: pool = cp;
056: classLoader = loader;
057: }
058:
059: /**
060: * Obtains the name of the annotation type.
061: */
062: public String getTypeName() {
063: return annotation.getTypeName();
064: }
065:
066: /**
067: * Obtains the internal data structure representing the annotation.
068: */
069: public Annotation getAnnotation() {
070: return annotation;
071: }
072:
073: /**
074: * Executes a method invocation on a proxy instance.
075: * The implementations of <code>toString()</code>, <code>equals()</code>,
076: * and <code>hashCode()</code> are directly supplied by the
077: * <code>AnnotationImpl</code>. The <code>annotationType()</code> method
078: * is also available on the proxy instance.
079: */
080: public Object invoke(Object proxy, Method method, Object[] args)
081: throws Throwable {
082: String name = method.getName();
083: if (Object.class == method.getDeclaringClass()) {
084: if ("equals".equals(name)) {
085: Object obj = args[0];
086: if (obj == null || obj instanceof Proxy == false)
087: return Boolean.FALSE;
088:
089: Object other = Proxy.getInvocationHandler(obj);
090: if (this .equals(other))
091: return Boolean.TRUE;
092: else
093: return Boolean.FALSE;
094: } else if ("toString".equals(name))
095: return annotation.getTypeName() + '@' + hashCode();
096: else if ("hashCode".equals(name))
097: return new Integer(hashCode());
098: } else if ("annotationType".equals(name)
099: && method.getParameterTypes().length == 0)
100: return classLoader.loadClass(getTypeName());
101:
102: MemberValue mv = annotation.getMemberValue(name);
103: if (mv == null)
104: return getDefault(name, method);
105: else
106: return mv.getValue(classLoader, pool, method);
107: }
108:
109: private Object getDefault(String name, Method method)
110: throws ClassNotFoundException, RuntimeException {
111: String classname = annotation.getTypeName();
112: if (pool != null)
113: try {
114: CtClass cc = pool.get(classname);
115: ClassFile cf = cc.getClassFile2();
116: MethodInfo minfo = cf.getMethod(name);
117: if (minfo != null) {
118: AnnotationDefaultAttribute ainfo = (AnnotationDefaultAttribute) minfo
119: .getAttribute(AnnotationDefaultAttribute.tag);
120: if (ainfo != null) {
121: MemberValue mv = ainfo.getDefaultValue();
122: return mv.getValue(classLoader, pool, method);
123: }
124: }
125: } catch (NotFoundException e) {
126: throw new RuntimeException("cannot find a class file: "
127: + classname);
128: }
129:
130: throw new RuntimeException("no default value: " + classname
131: + "." + name + "()");
132: }
133: }
|