All Downloads are FREE. Search and download functionalities are using the official Maven repository.

brooklyn.util.javalang.ReflectionScanner Maven / Gradle / Ivy

There is a newer version: 0.7.0-M1
Show newest version
package brooklyn.util.javalang;

import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

import org.reflections.ReflectionUtils;
import org.reflections.Reflections;
import org.reflections.Store;
import org.reflections.scanners.Scanner;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import brooklyn.util.text.Strings;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;

/** Facade on {@link Reflections} which logs warnings for unloadable classes but does not fail */
public class ReflectionScanner {

    private static final Logger log = LoggerFactory.getLogger(ReflectionScanner.class);
    
    protected final ClassLoader[] classLoaders;
    protected final Reflections reflections;

    /** scanner which will look in the given urls 
     * (or if those are null attempt to infer from the first entry in the classloaders,
     * although currently that seems to only pick up directories, not JAR's),
     * optionally filtering for the given prefix;
     * any or all arguments can be null to accept all (and use default classpath for classloading).
     **/
    public ReflectionScanner(
            final Iterable urlsToScan, 
            final String optionalPrefix,
            final ClassLoader ...classLoaders) {
        reflections = new Reflections(new ConfigurationBuilder() {
            {
                final Predicate filter = 
                        Strings.isNonEmpty(optionalPrefix) ? new FilterBuilder.Include(FilterBuilder.prefix(optionalPrefix)) : null;

                if (urlsToScan!=null)
                    setUrls(ImmutableSet.copyOf(urlsToScan));
                else if (classLoaders.length>0 && classLoaders[0]!=null)
                    setUrls(
                            ClasspathHelper.forPackage(Strings.isNonEmpty(optionalPrefix) ? optionalPrefix : "",
                                    asClassLoaderVarArgs(classLoaders[0])));
                
                if (filter!=null) filterInputsBy(filter);

                Scanner typeScanner = new TypeAnnotationsScanner();
                if (filter!=null) typeScanner = typeScanner.filterResultsBy(filter);
                Scanner subTypeScanner = new SubTypesScanner();
                if (filter!=null) subTypeScanner = subTypeScanner.filterResultsBy(filter);
                setScanners(typeScanner, subTypeScanner);
                
                for (ClassLoader cl: classLoaders)
                    if (cl!=null) addClassLoader(cl);
            }
        });
        this.classLoaders = Iterables.toArray(Iterables.filter(Arrays.asList(classLoaders), Predicates.notNull()), ClassLoader.class);
    }

    private static ClassLoader[] asClassLoaderVarArgs(final ClassLoader classLoaderToSearch) {
        return classLoaderToSearch==null ? new ClassLoader[0] : new ClassLoader[] { classLoaderToSearch };
    }

    public Store getStore() {
        return reflections.getStore();
    }
    
    /** overrides delegate so as to log rather than throw exception if a class cannot be loaded */
    public  Set> getSubTypesOf(final Class type) {
        Set subTypes = getStore().getSubTypesOf(type.getName());
        return ImmutableSet.copyOf(this.forNames(subTypes, "sub-type of "+type));
    }
    
    /** overrides delegate so as to log rather than throw exception if a class cannot be loaded */
    public Set> getTypesAnnotatedWith(Class annotation) {
        Set annotatedWith = getStore().getTypesAnnotatedWith(annotation.getName());
        return ImmutableSet.copyOf(this.forNames(annotatedWith, "annotated "+annotation.getName()));
    }

    @SuppressWarnings("unchecked")
    protected  List> forNames(Set classNames, final String context) {
        List> result = new ArrayList>();
        for (String className : classNames) {
            //noinspection unchecked
            try {
                Class clazz = (Class) loadClass(className);
                if (clazz != null) {
                    result.add(clazz);
                } else {
                    log.warn("Unable to instantiate '"+className+"' ("+context+")");
                }
            } catch (Throwable e) {
                log.warn("Unable to instantiate '"+className+"' ("+context+"): "+e);
            }
        }
        return result;
    }
    
    protected Class loadClass(String className) {
        return ReflectionUtils.forName(className, classLoaders);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy