001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.annotation;
016    
017    import java.lang.annotation.Annotation;
018    import java.lang.reflect.Method;
019    
020    import java.util.ArrayList;
021    import java.util.LinkedList;
022    import java.util.List;
023    import java.util.Queue;
024    
025    /**
026     * @author Shuyang Zhou
027     */
028    public class AnnotationLocator {
029    
030            public static List<Annotation> locate(Class<?> targetClass) {
031                    Queue<Class<?>> queue = new LinkedList<Class<?>>();
032    
033                    queue.offer(targetClass);
034    
035                    ArrayList<Annotation> annotationsList = new ArrayList<Annotation>();
036    
037                    Class<?> clazz = null;
038    
039                    while ((clazz = queue.poll()) != null) {
040                            Annotation[] annotations = clazz.getAnnotations();
041    
042                            _mergeAnnotations(annotations, annotationsList);
043    
044                            _queueSuperTypes(queue, clazz);
045                    }
046    
047                    annotationsList.trimToSize();
048    
049                    return annotationsList;
050            }
051    
052            public static <T extends Annotation> T locate(
053                    Class<?> targetClass, Class<T> annotationClass) {
054    
055                    Queue<Class<?>> queue = new LinkedList<Class<?>>();
056    
057                    queue.offer(targetClass);
058    
059                    Class<?> clazz = null;
060    
061                    while ((clazz = queue.poll()) != null) {
062                            T annotation = clazz.getAnnotation(annotationClass);
063    
064                            if (annotation == null) {
065                                    _queueSuperTypes(queue, clazz);
066                            }
067                            else {
068                                    return annotation;
069                            }
070                    }
071    
072                    return null;
073            }
074    
075            public static List<Annotation> locate(Method method, Class<?> targetClass) {
076                    Queue<Class<?>> queue = new LinkedList<Class<?>>();
077    
078                    if (targetClass == null) {
079                            queue.offer(method.getDeclaringClass());
080                    }
081                    else {
082                            queue.offer(targetClass);
083                    }
084    
085                    ArrayList<Annotation> annotationsList = new ArrayList<Annotation>();
086    
087                    Class<?> clazz = null;
088    
089                    while ((clazz = queue.poll()) != null) {
090                            try {
091                                    Method specificMethod = clazz.getDeclaredMethod(
092                                            method.getName(), method.getParameterTypes());
093    
094                                    Annotation[] annotations = specificMethod.getAnnotations();
095    
096                                    _mergeAnnotations(annotations, annotationsList);
097                            }
098                            catch (Exception e) {
099                            }
100    
101                            try {
102    
103                                    // Ensure the class has a publicly inherited method
104    
105                                    clazz.getMethod(method.getName(), method.getParameterTypes());
106    
107                                    Annotation[] annotations = clazz.getAnnotations();
108    
109                                    _mergeAnnotations(annotations, annotationsList);
110                            }
111                            catch (Exception e) {
112                            }
113    
114                            _queueSuperTypes(queue, clazz);
115                    }
116    
117                    annotationsList.trimToSize();
118    
119                    return annotationsList;
120            }
121    
122            public static <T extends Annotation> T locate(
123                    Method method, Class<?> targetClass, Class<T> annotationClass) {
124    
125                    Queue<Class<?>> queue = new LinkedList<Class<?>>();
126    
127                    if (targetClass == null) {
128                            queue.offer(method.getDeclaringClass());
129                    }
130                    else {
131                            queue.offer(targetClass);
132                    }
133    
134                    Class<?> clazz = null;
135    
136                    while ((clazz = queue.poll()) != null) {
137                            T annotation = null;
138    
139                            try {
140                                    Method specificMethod = clazz.getDeclaredMethod(
141                                            method.getName(), method.getParameterTypes());
142    
143                                    annotation = specificMethod.getAnnotation(annotationClass);
144    
145                                    if (annotation != null) {
146                                            return annotation;
147                                    }
148                            }
149                            catch (Exception e) {
150                            }
151    
152                            try {
153    
154                                    // Ensure the class has a publicly inherited method
155    
156                                    clazz.getMethod(method.getName(), method.getParameterTypes());
157    
158                                    annotation = clazz.getAnnotation(annotationClass);
159                            }
160                            catch (Exception e) {
161                            }
162    
163                            if (annotation == null) {
164                                    _queueSuperTypes(queue, clazz);
165                            }
166                            else {
167                                    return annotation;
168                            }
169                    }
170    
171                    return null;
172            }
173    
174            private static void _mergeAnnotations(
175                    Annotation[] sourceAnnotations, List<Annotation> targetAnnotationList) {
176    
177                    merge:
178                    for (Annotation sourceAnnotation : sourceAnnotations) {
179                            for (Annotation targetAnnotation : targetAnnotationList) {
180                                    if (sourceAnnotation.annotationType() ==
181                                                    targetAnnotation.annotationType()) {
182    
183                                            continue merge;
184                                    }
185                            }
186    
187                            targetAnnotationList.add(sourceAnnotation);
188                    }
189            }
190    
191            private static void _queueSuperTypes(
192                    Queue<Class<?>> queue, Class<?> clazz) {
193    
194                    Class<?> supperClass = clazz.getSuperclass();
195    
196                    if ((supperClass != null) && (supperClass != Object.class)) {
197                            queue.offer(supperClass);
198                    }
199    
200                    Class<?>[] interfaceClasses = clazz.getInterfaces();
201    
202                    for (Class<?> interfaceClass : interfaceClasses) {
203                            if (!queue.contains(interfaceClass)) {
204                                    queue.offer(interfaceClass);
205                            }
206                    }
207            }
208    
209    }