169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/*
269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit.
369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version
669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with
769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License.  Alternatively, the contents of this file may be used under
869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later.
969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis,
1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the
1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License.
1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist.bytecode.annotation;
1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.reflect.InvocationHandler;
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.reflect.Method;
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.reflect.Proxy;
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.ClassPool;
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.CtClass;
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.NotFoundException;
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.AnnotationDefaultAttribute;
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.ClassFile;
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.MethodInfo;
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/**
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Internal-use only.  This is a helper class internally used for implementing
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>toAnnotationType()</code> in <code>Annotation</code>.
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @author Shigeru Chiba
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @author <a href="mailto:bill@jboss.org">Bill Burke</a>
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @author <a href="mailto:adrian@jboss.org">Adrian Brock</a>
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class AnnotationImpl implements InvocationHandler {
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final String JDK_ANNOTATION_CLASS_NAME = "java.lang.annotation.Annotation";
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static Method JDK_ANNOTATION_TYPE_METHOD = null;
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Annotation annotation;
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private ClassPool pool;
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private ClassLoader classLoader;
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private transient Class annotationType;
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private transient int cachedHashCode = Integer.MIN_VALUE;
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    static {
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // Try to resolve the JDK annotation type method
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Class clazz = Class.forName(JDK_ANNOTATION_CLASS_NAME);
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            JDK_ANNOTATION_TYPE_METHOD = clazz.getMethod("annotationType", (Class[])null);
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (Exception ignored) {
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            // Probably not JDK5+
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Constructs an annotation object.
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param cl        class loader for obtaining annotation types.
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param clazz     the annotation type.
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param cp        class pool for containing an annotation
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                  type (or null).
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param anon      the annotation.
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return the annotation
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public static Object make(ClassLoader cl, Class clazz, ClassPool cp,
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                              Annotation anon) {
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        AnnotationImpl handler = new AnnotationImpl(anon, cp, cl);
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return Proxy.newProxyInstance(cl, new Class[] { clazz }, handler);
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private AnnotationImpl(Annotation a, ClassPool cp, ClassLoader loader) {
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        annotation = a;
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        pool = cp;
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        classLoader = loader;
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Obtains the name of the annotation type.
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return the type name
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public String getTypeName() {
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return annotation.getTypeName();
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Get the annotation type
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return the annotation class
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @throws NoClassDefFoundError when the class could not loaded
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Class getAnnotationType() {
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (annotationType == null) {
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            String typeName = annotation.getTypeName();
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            try {
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                annotationType = classLoader.loadClass(typeName);
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            catch (ClassNotFoundException e) {
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                NoClassDefFoundError error = new NoClassDefFoundError("Error loading annotation class: " + typeName);
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                error.setStackTrace(e.getStackTrace());
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                throw error;
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return annotationType;
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Obtains the internal data structure representing the annotation.
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return the annotation
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Annotation getAnnotation() {
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return annotation;
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Executes a method invocation on a proxy instance.
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * The implementations of <code>toString()</code>, <code>equals()</code>,
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * and <code>hashCode()</code> are directly supplied by the
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <code>AnnotationImpl</code>.  The <code>annotationType()</code> method
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * is also available on the proxy instance.
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Object invoke(Object proxy, Method method, Object[] args)
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws Throwable
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String name = method.getName();
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (Object.class == method.getDeclaringClass()) {
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if ("equals".equals(name)) {
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                Object obj = args[0];
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return new Boolean(checkEquals(obj));
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            else if ("toString".equals(name))
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return annotation.toString();
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            else if ("hashCode".equals(name))
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return new Integer(hashCode());
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else if ("annotationType".equals(name)
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                 && method.getParameterTypes().length == 0)
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal           return getAnnotationType();
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        MemberValue mv = annotation.getMemberValue(name);
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (mv == null)
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return getDefault(name, method);
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return mv.getValue(classLoader, pool, method);
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Object getDefault(String name, Method method)
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws ClassNotFoundException, RuntimeException
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String classname = annotation.getTypeName();
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (pool != null) {
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            try {
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                CtClass cc = pool.get(classname);
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                ClassFile cf = cc.getClassFile2();
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                MethodInfo minfo = cf.getMethod(name);
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                if (minfo != null) {
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    AnnotationDefaultAttribute ainfo
16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        = (AnnotationDefaultAttribute)
16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                          minfo.getAttribute(AnnotationDefaultAttribute.tag);
16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    if (ainfo != null) {
16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        MemberValue mv = ainfo.getDefaultValue();
16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        return mv.getValue(classLoader, pool, method);
16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    }
16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            catch (NotFoundException e) {
17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                throw new RuntimeException("cannot find a class file: "
17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                           + classname);
17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throw new RuntimeException("no default value: " + classname + "."
17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                   + name + "()");
17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns a hash code value for this object.
18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public int hashCode() {
18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (cachedHashCode == Integer.MIN_VALUE) {
18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int hashCode = 0;
18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            // Load the annotation class
18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            getAnnotationType();
18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Method[] methods = annotationType.getDeclaredMethods();
19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            for (int i = 0; i < methods.length; ++ i) {
19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                String name = methods[i].getName();
19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                int valueHashCode = 0;
19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                // Get the value
19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                MemberValue mv = annotation.getMemberValue(name);
19769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                Object value = null;
19869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                try {
19969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                   if (mv != null)
20069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                       value = mv.getValue(classLoader, pool, methods[i]);
20169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                   if (value == null)
20269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                       value = getDefault(name, methods[i]);
20369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
20469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                catch (RuntimeException e) {
20569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    throw e;
20669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
20769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                catch (Exception e) {
20869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    throw new RuntimeException("Error retrieving value " + name + " for annotation " + annotation.getTypeName(), e);
20969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
21069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
21169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                // Calculate the hash code
21269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                if (value != null) {
21369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    if (value.getClass().isArray())
21469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        valueHashCode = arrayHashCode(value);
21569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    else
21669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        valueHashCode = value.hashCode();
21769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
21869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                hashCode += 127 * name.hashCode() ^ valueHashCode;
21969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
22069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
22169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            cachedHashCode = hashCode;
22269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
22369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return cachedHashCode;
22469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
22569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
22669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
22769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Check that another annotation equals ourselves.
22869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
22969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param obj the other annotation
23069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return the true when equals false otherwise
23169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @throws Exception for any problem
23269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
23369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private boolean checkEquals(Object obj) throws Exception {
23469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (obj == null)
23569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return false;
23669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
23769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // Optimization when the other is one of ourselves
23869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (obj instanceof Proxy) {
23969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            InvocationHandler ih = Proxy.getInvocationHandler(obj);
24069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (ih instanceof AnnotationImpl) {
24169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                AnnotationImpl other = (AnnotationImpl) ih;
24269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return annotation.equals(other.annotation);
24369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
24469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
24569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
24669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class otherAnnotationType = (Class) JDK_ANNOTATION_TYPE_METHOD.invoke(obj, (Object[])null);
24769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (getAnnotationType().equals(otherAnnotationType) == false)
24869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal           return false;
24969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
25069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Method[] methods = annotationType.getDeclaredMethods();
25169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < methods.length; ++ i) {
25269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            String name = methods[i].getName();
25369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
25469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            // Get the value
25569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            MemberValue mv = annotation.getMemberValue(name);
25669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Object value = null;
25769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Object otherValue = null;
25869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            try {
25969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal               if (mv != null)
26069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                   value = mv.getValue(classLoader, pool, methods[i]);
26169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal               if (value == null)
26269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                   value = getDefault(name, methods[i]);
26369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal               otherValue = methods[i].invoke(obj, (Object[])null);
26469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
26569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            catch (RuntimeException e) {
26669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                throw e;
26769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
26869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            catch (Exception e) {
26969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                throw new RuntimeException("Error retrieving value " + name + " for annotation " + annotation.getTypeName(), e);
27069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
27169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
27269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (value == null && otherValue != null)
27369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return false;
27469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (value != null && value.equals(otherValue) == false)
27569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return false;
27669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
27769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
27869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return true;
27969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
28069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
28169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
28269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Calculates the hashCode of an array using the same
28369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * algorithm as java.util.Arrays.hashCode()
28469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
28569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param object the object
28669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return the hashCode
28769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
28869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static int arrayHashCode(Object object)
28969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
29069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal       if (object == null)
29169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal          return 0;
29269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
29369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal       int result = 1;
29469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
29569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal       Object[] array = (Object[]) object;
29669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal       for (int i = 0; i < array.length; ++i) {
29769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal           int elementHashCode = 0;
29869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal           if (array[i] != null)
29969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal              elementHashCode = array[i].hashCode();
30069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal           result = 31 * result + elementHashCode;
30169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal       }
30269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal       return result;
30369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
30469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
305