/** * The MIT License * * Copyright (C) 2007 Asterios Raptis * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.alpharogroup.lang; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.lang.annotation.Annotation; import java.util.HashSet; import java.util.List; import java.util.Set; import de.alpharogroup.file.FilenameUtils; import de.alpharogroup.file.filter.ClassFileFilter; /** * The Class AnnotationUtils. * * @author Asterios Raptis */ public final class AnnotationUtils { /** * Gets all annotated classes that belongs from the given package path and the given annotation * class. * * @param packagePath * the package path * @param annotationClass * the annotation class * @return the all classes * @throws ClassNotFoundException * the class not found exception * @throws IOException * Signals that an I/O exception has occurred. */ public static Set<Class<?>> getAllAnnotatedClasses(final String packagePath, final Class<? extends Annotation> annotationClass) throws ClassNotFoundException, IOException { final List<File> directories = ClassExtensions.getDirectoriesFromResources(packagePath, true); final Set<Class<?>> classes = new HashSet<>(); for (final File directory : directories) { classes.addAll(scanForAnnotatedClasses(directory, packagePath, annotationClass)); } return classes; } /** * Gets all annotated classes that belongs from the given package path and the given list with * annotation classes. * * @param packagePath * the package path * @param annotationClasses * the list with the annotation classes * @return the all classes * @throws ClassNotFoundException * the class not found exception * @throws IOException * Signals that an I/O exception has occurred. */ public static Set<Class<?>> getAllAnnotatedClassesFromSet(final String packagePath, final Set<Class<? extends Annotation>> annotationClasses) throws ClassNotFoundException, IOException { final List<File> directories = ClassExtensions.getDirectoriesFromResources(packagePath, true); final Set<Class<?>> classes = new HashSet<>(); for (final File directory : directories) { classes .addAll(scanForAnnotatedClassesFromSet(directory, packagePath, annotationClasses)); } return classes; } /** * Gets all the classes from the class loader that belongs to the given package path. * * @param packagePath * the package path * * @return the all classes * * @throws ClassNotFoundException * the class not found exception * @throws IOException * Signals that an I/O exception has occurred. */ public static Set<Class<?>> getAllClasses(final String packagePath) throws ClassNotFoundException, IOException { return getAllAnnotatedClasses(packagePath, null); } /** * Gets all the classes from the class loader that belongs to the given package path. * * @param packagePath * the package path * @param annotationClasses * the annotation classes * @return the all classes * @throws ClassNotFoundException * the class not found exception * @throws IOException * Signals that an I/O exception has occurred. */ public static Set<Class<?>> getAllClasses(final String packagePath, final Set<Class<? extends Annotation>> annotationClasses) throws ClassNotFoundException, IOException { return getAllAnnotatedClassesFromSet(packagePath, annotationClasses); } /** * Search for the given annotationClass in the given componentClass and return it if search was * successful. * * @param <T> * the generic type * @param componentClass * the component class * @param annotationClass * the annotation class * @return the annotation */ public static <T extends Annotation> T getAnnotation(final Class<?> componentClass, final Class<T> annotationClass) { T annotation = componentClass.getAnnotation(annotationClass); if (annotation != null) { return annotation; } for (final Class<?> ifc : componentClass.getInterfaces()) { annotation = getAnnotation(ifc, annotationClass); if (annotation != null) { return annotation; } } if (!Annotation.class.isAssignableFrom(componentClass)) { for (final Annotation ann : componentClass.getAnnotations()) { annotation = getAnnotation(ann.annotationType(), annotationClass); if (annotation != null) { return annotation; } } } final Class<?> superClass = componentClass.getSuperclass(); if (superClass == null || superClass.equals(Object.class)) { return null; } return getAnnotation(superClass, annotationClass); } /** * Checks if is annotation present through making a lookup if the given annotation class is * present in the given class or in one of the super classes. * * @param componentClass * the component class * @param annotationClass * the annotation class * @return true, if is annotation present */ public static boolean isAnnotationPresentInSuperClasses(final Class<?> componentClass, final Class<? extends Annotation> annotationClass) { if (componentClass.isAnnotationPresent(annotationClass)) { return true; } Class<?> superClass = componentClass.getSuperclass(); while (superClass != null) { if (superClass.isAnnotationPresent(annotationClass)) { return true; } superClass = superClass.getSuperclass(); } return false; } /** * Checks if is annotation present through making a lookup if the given annotation class is * present in the given class or in one of the super classes. * * @param componentClass * the component class * @param annotationClass * the annotation class * @return true, if is annotation present */ public static boolean isAnnotationPresentInSuperClassesOrInterfaces( final Class<?> componentClass, final Class<? extends Annotation> annotationClass) { return getAnnotation(componentClass, annotationClass) != null; } /** * Scan recursive for annotated classes in the given directory. * * @param directory * the directory * @param packagePath * the package path * @param annotationClass * the annotation class * @return the list * @throws ClassNotFoundException * the class not found exception */ public static Set<Class<?>> scanForAnnotatedClasses(final File directory, final String packagePath, final Class<? extends Annotation> annotationClass) throws ClassNotFoundException { final Set<Class<?>> foundClasses = new HashSet<>(); if (!directory.exists()) { return foundClasses; } // define the include filefilter for class files... final FileFilter includeFileFilter = new ClassFileFilter(); final File[] files = directory.listFiles(includeFileFilter); for (final File file : files) { String qualifiedClassname = null; if (file.isDirectory()) { qualifiedClassname = packagePath + "." + file.getName(); foundClasses.addAll(scanForAnnotatedClasses(file, qualifiedClassname, annotationClass)); } else { final String filename = FilenameUtils.getFilenameWithoutExtension(file); qualifiedClassname = packagePath + '.' + filename; Class<?> foundClass = null; try { foundClass = Class.forName(qualifiedClassname); if (null != annotationClass) { if (foundClass.isAnnotationPresent(annotationClass)) { foundClasses.add(foundClass); } } else { foundClasses.add(foundClass); } } catch (final Throwable throwable) { foundClass = Class.forName(qualifiedClassname, false, ClassExtensions.getClassLoader()); if (null != annotationClass) { if (foundClass.isAnnotationPresent(annotationClass)) { foundClasses.add(foundClass); } } else { foundClasses.add(foundClass); } } } } return foundClasses; } /** * Scan recursive for annotated classes in the given directory. * * @param directory * the directory * @param packagePath * the package path * @param annotationClasses * the list with the annotation classes * @return the list * @throws ClassNotFoundException * the class not found exception */ public static Set<Class<?>> scanForAnnotatedClassesFromSet(final File directory, final String packagePath, final Set<Class<? extends Annotation>> annotationClasses) throws ClassNotFoundException { final Set<Class<?>> foundClasses = new HashSet<>(); if (!directory.exists()) { return foundClasses; } // define the include filefilter for class files... final FileFilter includeFileFilter = new ClassFileFilter(); final File[] files = directory.listFiles(includeFileFilter); for (final File file : files) { String qualifiedClassname = null; if (file.isDirectory()) { qualifiedClassname = packagePath + "." + file.getName(); foundClasses.addAll(scanForAnnotatedClassesFromSet(file, qualifiedClassname, annotationClasses)); } else { final String filename = FilenameUtils.getFilenameWithoutExtension(file); qualifiedClassname = packagePath + '.' + filename; Class<?> foundClass = null; try { foundClass = Class.forName(qualifiedClassname); if (null != annotationClasses) { for (final Class<? extends Annotation> annotationClass : annotationClasses) { if (foundClass.isAnnotationPresent(annotationClass)) { foundClasses.add(foundClass); } } } else { foundClasses.add(foundClass); } } catch (final Throwable throwable) { foundClass = Class.forName(qualifiedClassname, false, ClassExtensions.getClassLoader()); if (null != annotationClasses) { for (final Class<? extends Annotation> annotationClass : annotationClasses) { if (foundClass.isAnnotationPresent(annotationClass)) { foundClasses.add(foundClass); } } } else { foundClasses.add(foundClass); } } } } return foundClasses; } /** * Scan recursive for classes in the given directory. * * @param directory * the directory * @param packagePath * the package path * @return the list * @throws ClassNotFoundException * the class not found exception */ public static Set<Class<?>> scanForClasses(final File directory, final String packagePath) throws ClassNotFoundException { return AnnotationUtils.scanForAnnotatedClasses(directory, packagePath, null); } /** * Private constructor. */ private AnnotationUtils() { super(); } }