001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.camel.util;
018
019import java.lang.annotation.Annotation;
020import java.lang.reflect.AnnotatedElement;
021import java.lang.reflect.Field;
022import java.lang.reflect.Method;
023import java.util.ArrayList;
024import java.util.List;
025
026public final class AnnotationHelper {
027
028    /**
029     * Returns a list of methods which are annotated with the given annotation
030     *
031     * @param  type           the type to reflect on
032     * @param  annotationType the annotation type
033     * @return                a list of the methods found
034     */
035    public static List<Method> findMethodsWithAnnotation(
036            Class<?> type,
037            Class<? extends Annotation> annotationType) {
038        return findMethodsWithAnnotation(type, annotationType, false);
039    }
040
041    /**
042     * Returns a list of methods which are annotated with the given annotation
043     *
044     * @param  type                 the type to reflect on
045     * @param  annotationType       the annotation type
046     * @param  checkMetaAnnotations check for meta annotations
047     * @return                      a list of the methods found
048     */
049    public static List<Method> findMethodsWithAnnotation(
050            Class<?> type,
051            Class<? extends Annotation> annotationType,
052            boolean checkMetaAnnotations) {
053        List<Method> answer = new ArrayList<>();
054        do {
055            Method[] methods = type.getDeclaredMethods();
056            for (Method method : methods) {
057                if (hasAnnotation(method, annotationType, checkMetaAnnotations)) {
058                    answer.add(method);
059                }
060            }
061            type = type.getSuperclass();
062        } while (type != null);
063        return answer;
064    }
065
066    /**
067     * Checks if a Class or Method are annotated with the given annotation
068     *
069     * @param  elem                 the Class or Method to reflect on
070     * @param  annotationType       the annotation type
071     * @param  checkMetaAnnotations check for meta annotations
072     * @return                      true if annotations is present
073     */
074    public static boolean hasAnnotation(
075            AnnotatedElement elem, Class<? extends Annotation> annotationType,
076            boolean checkMetaAnnotations) {
077        if (elem.isAnnotationPresent(annotationType)) {
078            return true;
079        }
080        if (checkMetaAnnotations) {
081            for (Annotation a : elem.getAnnotations()) {
082                for (Annotation meta : a.annotationType().getAnnotations()) {
083                    // NOTE: we perform an equality check as, by design, this has
084                    // to be also supported in OSGI environments, therefore, instance equality may differ.
085                    if (meta.annotationType().getName().equals(annotationType.getName())) { // NOSONAR
086                        return true;
087                    }
088                }
089            }
090        }
091        return false;
092    }
093
094    /**
095     * Checks if the class has been annotated with the given annotation (FQN class name) and if present, then returns
096     * the value attribute.
097     *
098     * @param  clazz             the class
099     * @param  fqnAnnotationName the FQN of the annotation
100     * @return                   null if not annotated, otherwise the value, an empty string means annotation but has no
101     *                           value
102     */
103    public static String getAnnotationValue(Class<?> clazz, String fqnAnnotationName) {
104        for (Annotation ann : clazz.getAnnotations()) {
105            if (ann.annotationType().getName().equals(fqnAnnotationName)) {
106                String s = ann.toString();
107                return StringHelper.between(s, "\"", "\"");
108            }
109        }
110        return null;
111    }
112
113    /**
114     * Checks if the class has been annotated with the given annotation (FQN class name).
115     *
116     * @param  clazz             the class
117     * @param  fqnAnnotationName the FQN of the annotation
118     * @return                   true if annotated or false if not
119     */
120    public static boolean hasAnnotation(Class<?> clazz, String fqnAnnotationName) {
121        for (Annotation ann : clazz.getAnnotations()) {
122            if (ann.annotationType().getName().equals(fqnAnnotationName)) {
123                return true;
124            }
125        }
126        return false;
127    }
128
129    /**
130     * Checks if the method has been annotated with the given annotation (FQN class name).
131     *
132     * @param  method            the method
133     * @param  fqnAnnotationName the FQN of the annotation
134     * @return                   true if annotated or false if not
135     */
136    public static boolean hasAnnotation(Method method, String fqnAnnotationName) {
137        for (Annotation ann : method.getAnnotations()) {
138            if (ann.annotationType().getName().equals(fqnAnnotationName)) {
139                return true;
140            }
141        }
142        return false;
143    }
144
145    /**
146     * Checks if the method has been annotated with the given annotation (FQN class name) and if present, then returns
147     * the value attribute.
148     *
149     * @param  method            the method
150     * @param  fqnAnnotationName the FQN of the annotation
151     * @return                   null if not annotated, otherwise the value, an empty string means annotation but has no
152     *                           value
153     */
154    public static String getAnnotationValue(Method method, String fqnAnnotationName) {
155        return (String) getAnnotationValue(method, fqnAnnotationName, "value");
156    }
157
158    /**
159     * Checks if the method has been annotated with the given annotation (FQN class name) and if present, then returns
160     * the value attribute.
161     *
162     * @param  method            the field
163     * @param  key               the annotation key
164     * @param  fqnAnnotationName the FQN of the annotation
165     * @return                   null if not annotated, otherwise the value, an empty string means annotation but has no
166     *                           value
167     */
168    public static Object getAnnotationValue(Method method, String fqnAnnotationName, String key) {
169        for (Annotation ann : method.getAnnotations()) {
170            if (ann.annotationType().getName().equals(fqnAnnotationName)) {
171                try {
172                    Method m = ann.getClass().getDeclaredMethod(key);
173                    return m.invoke(ann);
174                } catch (Exception e) {
175                    return null;
176                }
177            }
178        }
179        return null;
180    }
181
182    /**
183     * Checks if the field has been annotated with the given annotation (FQN class name).
184     *
185     * @param  field             the field
186     * @param  fqnAnnotationName the FQN of the annotation
187     * @return                   true if annotated or false if not
188     */
189    public static boolean hasAnnotation(Field field, String fqnAnnotationName) {
190        for (Annotation ann : field.getAnnotations()) {
191            if (ann.annotationType().getName().equals(fqnAnnotationName)) {
192                return true;
193            }
194        }
195        return false;
196    }
197
198    /**
199     * Checks if the field has been annotated with the given annotation (FQN class name) and if present, then returns
200     * the value attribute.
201     *
202     * @param  field             the field
203     * @param  fqnAnnotationName the FQN of the annotation
204     * @return                   null if not annotated, otherwise the value, an empty string means annotation but has no
205     *                           value
206     */
207    public static String getAnnotationValue(Field field, String fqnAnnotationName) {
208        return (String) getAnnotationValue(field, fqnAnnotationName, "value");
209    }
210
211    /**
212     * Checks if the field has been annotated with the given annotation (FQN class name) and if present, then returns
213     * the value attribute.
214     *
215     * @param  field             the field
216     * @param  key               the annotation key
217     * @param  fqnAnnotationName the FQN of the annotation
218     * @return                   null if not annotated, otherwise the value, an empty string means annotation but has no
219     *                           value
220     */
221    public static Object getAnnotationValue(Field field, String fqnAnnotationName, String key) {
222        for (Annotation ann : field.getAnnotations()) {
223            if (ann.annotationType().getName().equals(fqnAnnotationName)) {
224                try {
225                    Method m = ann.getClass().getDeclaredMethod(key);
226                    return m.invoke(ann);
227                } catch (Exception e) {
228                    return null;
229                }
230            }
231        }
232        return null;
233    }
234
235}