/** * Copyright (c) 2014 by the original author or authors. * * This code is free software; you can redistribute it and/or modify it under the terms of the * GNU Lesser General Public License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * 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 ch.sdi.core.util; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.util.StringUtils; /** * Provides some static methods for dealing with classes * <p> * * @version 1.0 (07.11.2014) * @author Heri */ public class ClassUtil { /** logger for this class */ private static Logger myLog = LogManager.getLogger( ClassUtil.class ); /** * Constructor * */ public ClassUtil() { super(); } /** * Lists all types in the given package (recursive) which are annotated by the given annotation and * are assignable from given class. * <p> * All types which match the criteria are returned, no further checks (interface, abstract, embedded, * etc. are performed. * <p> * * @param aClass * the desired (base) class * @param aAnnotation * the desired annotation type * @param aRoot * the package name where to start the search. Must not be empty. And not start * with 'org.springframework' (cannot parse springs library itself). * @return a list of found types */ @SuppressWarnings( "unchecked" ) public static <T> Collection<Class<T>> findCandidatesByAnnotation( Class<T> aClass, Class<? extends Annotation> aAnnotation, String aRoot ) { Collection<Class<T>> result = new ArrayList<Class<T>>(); Collection<? extends Class<?>> candidates = findCandidatesByAnnotation( aAnnotation, aRoot ); candidates.stream() .peek( c -> myLog.trace( "inspecting candidate " + c.getName() ) ) .filter( c -> aClass.isAssignableFrom( c ) ) .peek( c -> myLog.debug( "candidate " + c.getName() + " is of desired type" ) ) .forEach( c -> result.add( (Class<T>) c ) ); return result; } /** * Lists all types in the given package (recursive) which are annotated by the given annotation. * <p> * All types which match the criteria are returned, no further checks (interface, abstract, embedded, etc. * are performed. * <p> * * @param aAnnotation * the desired annotation type * @param aRoot * the package name where to start the search. Must not be empty. And not start * with 'org.springframework' (cannot parse springs library itself). * @return a list of found types */ public static Collection<? extends Class<?>> findCandidatesByAnnotation( Class<? extends Annotation> aAnnotation, String aRoot ) { if ( !StringUtils.hasText( aRoot ) ) { throw new IllegalArgumentException( "aRoot must not be empty (cannot parse spring library classes)" ); } // if StringUtils.hasText( aRoot ) if ( aRoot.startsWith( "org.springframework" ) ) { throw new IllegalArgumentException( "cannot parse spring library classes" ); } // if StringUtils.hasText( aRoot ) List<Class<?>> result = new ArrayList<Class<?>>(); MyClassScanner scanner = new MyClassScanner(); scanner.addIncludeFilter( new AnnotationTypeFilter( aAnnotation ) ); Set<BeanDefinition> canditates = scanner.findCandidateComponents( aRoot ); for ( BeanDefinition beanDefinition : canditates ) { try { String classname = beanDefinition.getBeanClassName(); Class<?> clazz = Class.forName( classname ); result.add( clazz ); } catch ( ClassNotFoundException t ) { myLog.error( "Springs type scanner returns a class name whose class cannot be evaluated!!!", t ); } } return result; } static class MyClassScanner extends ClassPathScanningCandidateComponentProvider { /** * Constructor */ public MyClassScanner() { super( false ); } @Override protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { return true; } }; }