1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18d736c6d053f63e4cd8dfb16c57093c67be3e18cdElliott Hughespackage libcore.reflect;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.ObjectInputStream;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.Serializable;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.lang.annotation.Annotation;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.lang.annotation.IncompleteAnnotationException;
257365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.lang.reflect.InvocationHandler;
267365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.lang.reflect.Method;
277365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.lang.reflect.Proxy;
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.ArrayList;
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.List;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Map;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.WeakHashMap;
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The annotation implementation based on dynamically generated proxy instances.
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * It conforms to all requirements stated in public APIs, see in particular
36f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * {@link java.lang.reflect.AnnotatedElement java.lang.reflect.AnnotatedElement}
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * and {@link java.lang.annotation.Annotation java.lang.annotation.Annotation}.
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Namely, annotation instances are immutable and serializable; they provide
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * conforming access to annotation member values and required implementations of
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * methods declared in Annotation interface.
41f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
421dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes * @see AnnotationMember
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see java.lang.annotation.Annotation
44f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @author Alexey V. Varlamov, Serguei S. Zapreyev
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @version $Revision$
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project@SuppressWarnings({"serial"})
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic final class AnnotationFactory implements InvocationHandler, Serializable {
50f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
511dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes    private static final transient Map<Class<? extends Annotation>, AnnotationMember[]> cache =
521dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes            new WeakHashMap<Class<? extends Annotation>, AnnotationMember[]>();
53f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
55f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * Reflects specified annotation type and returns an array
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * of member element definitions with default values.
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
581dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes    public static AnnotationMember[] getElementsDescription(Class<? extends Annotation> annotationType) {
591dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes        synchronized (cache) {
601dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes            AnnotationMember[] desc = cache.get(annotationType);
611dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes            if (desc != null) {
621dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes                return desc;
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
641dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes        }
651dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes        if (!annotationType.isAnnotation()) {
661dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes            throw new IllegalArgumentException("Type is not annotation: " + annotationType.getName());
671dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes        }
681dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes        Method[] declaredMethods = annotationType.getDeclaredMethods();
691dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes        AnnotationMember[] desc = new AnnotationMember[declaredMethods.length];
701dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes        for (int i = 0; i < declaredMethods.length; ++i) {
711dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes            Method element = declaredMethods[i];
721dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes            String name = element.getName();
731dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes            Class<?> type = element.getReturnType();
741dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes            try {
751dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes                desc[i] = new AnnotationMember(name, element.getDefaultValue(), type, element);
761dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes            } catch (Throwable t) {
771dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes                desc[i] = new AnnotationMember(name, t, type, element);
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
791dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes        }
801dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes        synchronized (cache) {
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            cache.put(annotationType, desc);
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return desc;
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
85f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Provides a new annotation instance.
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param annotationType the annotation type definition
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param elements name-value pairs representing elements of the annotation
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a new annotation instance
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
9247f7d00f0edf404e1cac410334e1ea4d75a28b8dElliott Hughes    public static <A extends Annotation> A createAnnotation(Class<? extends Annotation> annotationType,
9347f7d00f0edf404e1cac410334e1ea4d75a28b8dElliott Hughes                                                            AnnotationMember[] elements) {
941dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes        AnnotationFactory factory = new AnnotationFactory(annotationType, elements);
9547f7d00f0edf404e1cac410334e1ea4d75a28b8dElliott Hughes        return (A) Proxy.newProxyInstance(annotationType.getClassLoader(),
9647f7d00f0edf404e1cac410334e1ea4d75a28b8dElliott Hughes                                          new Class[]{annotationType}, factory);
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final Class<? extends Annotation> klazz;
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private AnnotationMember[] elements;
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * New instances should not be created directly, use factory method
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #createAnnotation(Class, AnnotationMember[]) createAnnotation()}
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * instead.
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param klzz class defining the annotation type
108f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * @param values actual element values
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private AnnotationFactory(Class<? extends Annotation> klzz, AnnotationMember[] values) {
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        klazz = klzz;
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        AnnotationMember[] defs = getElementsDescription(klazz);
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (values == null) {
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            elements = defs;
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            //merge default and actual values
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            elements = new AnnotationMember[defs.length];
1181dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes            next: for (int i = elements.length - 1; i >= 0; i--) {
1191dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes                for (AnnotationMember val : values) {
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (val.name.equals(defs[i].name)) {
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        elements[i] = val.setDefinition(defs[i]);
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        continue next;
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                elements[i] = defs[i];
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
129f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
131f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * Reads the object, obtains actual member definitions for the annotation type,
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * and merges deserialized values with the new definitions.
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
1341dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes    private void readObject(ObjectInputStream os) throws IOException, ClassNotFoundException {
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        os.defaultReadObject();
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Annotation type members can be changed arbitrarily
137f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        // So there may be zombi elements from the previous life;
138f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        // they hardly fit into this new annotation's incarnation,
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // as we have no defining methods for them.
140f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        // Reasonably just drop such elements,
141f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        // but seems better to keep them for compatibility
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        AnnotationMember[] defs = getElementsDescription(klazz);
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        AnnotationMember[] old = elements;
1441dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes        List<AnnotationMember> merged = new ArrayList<AnnotationMember>(defs.length + old.length);
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        nextOld: for (AnnotationMember el1 : old) {
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (AnnotationMember el2 : defs) {
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (el2.name.equals(el1.name)) {
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    continue nextOld;
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            merged.add(el1); //phantom element
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1531dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes        nextNew: for (AnnotationMember def : defs) {
1541dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes            for (AnnotationMember val : old) {
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (val.name.equals(def.name)) {
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // nothing to do about cached errors (if any)
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // anyway they remain relevant to values
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    merged.add(val.setDefinition(def));
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    continue nextNew;
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            merged.add(def); // brand new element
163f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        }
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        elements = merged.toArray(new AnnotationMember[merged.size()]);
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
166f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns true if the specified object represents the same annotation instance.
169f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * That is, if it implements the same annotation type and
170f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * returns the same element values.
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <br>Note, actual underlying implementation mechanism does not matter - it may
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * differ completely from this class.
173f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * @return true if the passed object is equivalent annotation instance,
174f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * false otherwise.
1751dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes     * @see AnnotationMember#equals(Object)
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean equals(Object obj) {
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (obj == this) {
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return true;
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!klazz.isInstance(obj)) {
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return false;
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Object handler = null;
185f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        if (Proxy.isProxyClass(obj.getClass())
1861dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes                && (handler = Proxy.getInvocationHandler(obj)) instanceof AnnotationFactory) {
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            AnnotationFactory other = (AnnotationFactory) handler;
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (elements.length != other.elements.length) {
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return false;
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
1911dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes            next: for (AnnotationMember el1 : elements) {
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                for (AnnotationMember el2 : other.elements) {
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (el1.equals(el2)) {
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        continue next;
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return false;
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return true;
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
2011dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes            // encountered foreign annotation implementation
202f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            // so have to obtain element values via invocation
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // of corresponding methods
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (final AnnotationMember el : elements) {
2051dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes                if (el.tag == AnnotationMember.ERROR) {
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // undefined value is incomparable (transcendent)
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return false;
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                try {
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (!el.definingMethod.isAccessible()) {
211ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes                        el.definingMethod.setAccessible(true);
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    Object otherValue = el.definingMethod.invoke(obj);
2141dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes                    if (otherValue != null) {
2151dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes                        if (el.tag == AnnotationMember.ARRAY) {
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            if (!el.equalArrayValue(otherValue)) {
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                return false;
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            }
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        } else {
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            if (!el.value.equals(otherValue)) {
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                return false;
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            }
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    } else if (el.value != AnnotationMember.NO_VALUE) {
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        return false;
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } catch (Throwable e) {
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return false;
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return true;
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
236f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * Returns a hash code composed as a sum of hash codes of member elements,
237f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * including elements with default values.
2381dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes     * @see AnnotationMember#hashCode()
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int hashCode() {
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int hash = 0;
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (AnnotationMember element : elements) {
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            hash += element.hashCode();
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return hash;
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Provides detailed description of this annotation instance,
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * including all member name-values pairs.
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return string representation of this annotation
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String toString() {
2546aa068b481cc4cca7765ce90fdf32f3eb2b5a77cElliott Hughes        StringBuilder result = new StringBuilder();
2556aa068b481cc4cca7765ce90fdf32f3eb2b5a77cElliott Hughes        result.append('@');
2566aa068b481cc4cca7765ce90fdf32f3eb2b5a77cElliott Hughes        result.append(klazz.getName());
2576aa068b481cc4cca7765ce90fdf32f3eb2b5a77cElliott Hughes        result.append('(');
2580d4daefcf389b6433a0af481ef44a84a2546541aElliott Hughes        for (int i = 0; i < elements.length; ++i) {
2596aa068b481cc4cca7765ce90fdf32f3eb2b5a77cElliott Hughes            if (i != 0) {
2606aa068b481cc4cca7765ce90fdf32f3eb2b5a77cElliott Hughes                result.append(", ");
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
2626aa068b481cc4cca7765ce90fdf32f3eb2b5a77cElliott Hughes            result.append(elements[i]);
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
2646aa068b481cc4cca7765ce90fdf32f3eb2b5a77cElliott Hughes        result.append(')');
2656aa068b481cc4cca7765ce90fdf32f3eb2b5a77cElliott Hughes        return result.toString();
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
267f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Processes a method invocation request to this annotation instance.
270f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * Recognizes the methods declared in the
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link java.lang.annotation.Annotation java.lang.annotation.Annotation}
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * interface, and member-defining methods of the implemented annotation type.
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException If the specified method is none of the above
274f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * @return the invocation result
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
2761dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String name = method.getName();
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Class[] params = method.getParameterTypes();
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (params.length == 0) {
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if ("annotationType".equals(name)) {
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return klazz;
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else if ("toString".equals(name)) {
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return toString();
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else if ("hashCode".equals(name)) {
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return hashCode();
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
287f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // this must be element value request
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            AnnotationMember element = null;
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (AnnotationMember el : elements) {
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (name.equals(el.name)) {
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    element = el;
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    break;
294f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                }
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (element == null || !method.equals(element.definingMethod)) {
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new IllegalArgumentException(method.toString());
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Object value = element.validateValue();
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (value == null) {
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    throw new IncompleteAnnotationException(klazz, name);
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return value;
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
3051dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes        } else if (params.length == 1 && params[0] == Object.class && "equals".equals(name)) {
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return Boolean.valueOf(equals(args[0]));
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
3081dc4d34e7de05c95b31a39e54d915f20240a4746Elliott Hughes        throw new IllegalArgumentException("Invalid method for annotation type: " + method);
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
311