[java] Scanning Java annotations at runtime

What is the best way of searching the whole classpath for an annotated class?

I'm doing a library and I want to allow the users to annotate their classes, so when the Web application starts I need to scan the whole classpath for certain annotation.

Do you know a library or a Java facility to do this?

Edit: I'm thinking about something like the new functionality for Java EE 5 Web Services or EJB's. You annotate your class with @WebService or @EJB and the system finds these classes while loading so they are accessible remotely.

This question is related to java annotations classloader

The answer is


Google Reflection if you want to discover interfaces as well.

Spring ClassPathScanningCandidateComponentProvider is not discovering interfaces.


There's a wonderful comment by zapp that sinks in all those answers:

new Reflections("my.package").getTypesAnnotatedWith(MyAnnotation.class)

Spring has something called a AnnotatedTypeScanner class.
This class internally uses

ClassPathScanningCandidateComponentProvider

This class has the code for actual scanning of the classpath resources. It does this by using the class metadata available at runtime.

One can simply extend this class or use the same class for scanning. Below is the constructor definition.

/**
     * Creates a new {@link AnnotatedTypeScanner} for the given annotation types.
     * 
     * @param considerInterfaces whether to consider interfaces as well.
     * @param annotationTypes the annotations to scan for.
     */
    public AnnotatedTypeScanner(boolean considerInterfaces, Class<? extends Annotation>... annotationTypes) {

        this.annotationTypess = Arrays.asList(annotationTypes);
        this.considerInterfaces = considerInterfaces;
    }

The Classloader API doesn't have an "enumerate" method, because class loading is an "on-demand" activity -- you usually have thousands of classes in your classpath, only a fraction of which will ever be needed (the rt.jar alone is 48MB nowadays!).

So, even if you could enumerate all classes, this would be very time- and memory-consuming.

The simple approach is to list the concerned classes in a setup file (xml or whatever suits your fancy); if you want to do this automatically, restrict yourself to one JAR or one class directory.


Google Reflections seems to be much faster than Spring. Found this feature request that adresses this difference: http://www.opensaga.org/jira/browse/OS-738

This is a reason to use Reflections as startup time of my application is really important during development. Reflections seems also to be very easy to use for my use case (find all implementers of an interface).


Is it too late to answer. I would say, its better to go by Libraries like ClassPathScanningCandidateComponentProvider or like Scannotations

But even after somebody wants to try some hands on it with classLoader, I have written some on my own to print the annotations from classes in a package:

public class ElementScanner {

public void scanElements(){
    try {
    //Get the package name from configuration file
    String packageName = readConfig();

    //Load the classLoader which loads this class.
    ClassLoader classLoader = getClass().getClassLoader();

    //Change the package structure to directory structure
    String packagePath  = packageName.replace('.', '/');
    URL urls = classLoader.getResource(packagePath);

    //Get all the class files in the specified URL Path.
    File folder = new File(urls.getPath());
    File[] classes = folder.listFiles();

    int size = classes.length;
    List<Class<?>> classList = new ArrayList<Class<?>>();

    for(int i=0;i<size;i++){
        int index = classes[i].getName().indexOf(".");
        String className = classes[i].getName().substring(0, index);
        String classNamePath = packageName+"."+className;
        Class<?> repoClass;
        repoClass = Class.forName(classNamePath);
        Annotation[] annotations = repoClass.getAnnotations();
        for(int j =0;j<annotations.length;j++){
            System.out.println("Annotation in class "+repoClass.getName()+ " is "+annotations[j].annotationType().getName());
        }
        classList.add(repoClass);
    }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

/**
 * Unmarshall the configuration file
 * @return
 */
public String readConfig(){
    try{
        URL url = getClass().getClassLoader().getResource("WEB-INF/config.xml");
        JAXBContext jContext = JAXBContext.newInstance(RepositoryConfig.class);
         Unmarshaller um =  jContext.createUnmarshaller();
         RepositoryConfig rc = (RepositoryConfig) um.unmarshal(new File(url.getFile()));
         return rc.getRepository().getPackageName();
        }catch(Exception e){
            e.printStackTrace();
        }
    return null;

}
}

And in config File, you put the package name and unmarshall it to a class .


There's a wonderful comment by zapp that sinks in all those answers:

new Reflections("my.package").getTypesAnnotatedWith(MyAnnotation.class)

Google Reflection if you want to discover interfaces as well.

Spring ClassPathScanningCandidateComponentProvider is not discovering interfaces.


Spring has something called a AnnotatedTypeScanner class.
This class internally uses

ClassPathScanningCandidateComponentProvider

This class has the code for actual scanning of the classpath resources. It does this by using the class metadata available at runtime.

One can simply extend this class or use the same class for scanning. Below is the constructor definition.

/**
     * Creates a new {@link AnnotatedTypeScanner} for the given annotation types.
     * 
     * @param considerInterfaces whether to consider interfaces as well.
     * @param annotationTypes the annotations to scan for.
     */
    public AnnotatedTypeScanner(boolean considerInterfaces, Class<? extends Annotation>... annotationTypes) {

        this.annotationTypess = Arrays.asList(annotationTypes);
        this.considerInterfaces = considerInterfaces;
    }

You can find classes with any given annotation with ClassGraph, as well as searching for other criteria of interest, e.g. classes that implement a given interface. (Disclaimer, I am the author of ClassGraph.) ClassGraph can build an abstract representation of the entire class graph (all classes, annotations, methods, method parameters, and fields) in memory, for all classes on the classpath, or for classes in whitelisted packages, and you can query that class graph however you want. ClassGraph supports more classpath specification mechanisms and classloaders than any other scanner, and also works seamlessly with the new JPMS module system, so if you base your code on ClassGraph, your code will be maximally portable. See the API here.


You can use Java Pluggable Annotation Processing API to write annotation processor which will be executed during the compilation process and will collect all annotated classes and build the index file for runtime use.

This is the fastest way possible to do annotated class discovery because you don't need to scan your classpath at runtime, which is usually very slow operation. Also this approach works with any classloader and not only with URLClassLoaders usually supported by runtime scanners.

The above mechanism is already implemented in ClassIndex library.

To use it annotate your custom annotation with @IndexAnnotated meta-annotation. This will create at compile time an index file: META-INF/annotations/com/test/YourCustomAnnotation listing all annotated classes. You can acccess the index at runtime by executing:

ClassIndex.getAnnotated(com.test.YourCustomAnnotation.class)

You can use Java Pluggable Annotation Processing API to write annotation processor which will be executed during the compilation process and will collect all annotated classes and build the index file for runtime use.

This is the fastest way possible to do annotated class discovery because you don't need to scan your classpath at runtime, which is usually very slow operation. Also this approach works with any classloader and not only with URLClassLoaders usually supported by runtime scanners.

The above mechanism is already implemented in ClassIndex library.

To use it annotate your custom annotation with @IndexAnnotated meta-annotation. This will create at compile time an index file: META-INF/annotations/com/test/YourCustomAnnotation listing all annotated classes. You can acccess the index at runtime by executing:

ClassIndex.getAnnotated(com.test.YourCustomAnnotation.class)

If you're looking for an alternative to reflections I'd like to recommend Panda Utilities - AnnotationsScanner. It's a Guava-free (Guava has ~3MB, Panda Utilities has ~200kb) scanner based on the reflections library source code.

It's also dedicated for future-based searches. If you'd like to scan multiple times included sources or even provide an API, which allows someone scanning current classpath, AnnotationsScannerProcess caches all fetched ClassFiles, so it's really fast.

Simple example of AnnotationsScanner usage:

AnnotationsScanner scanner = AnnotationsScanner.createScanner()
        .includeSources(ExampleApplication.class)
        .build();

AnnotationsScannerProcess process = scanner.createWorker()
        .addDefaultProjectFilters("net.dzikoysk")
        .fetch();

Set<Class<?>> classes = process.createSelector()
        .selectTypesAnnotatedWith(AnnotationTest.class);

And another solution is Google reflections.

Quick review:

  • Spring solution is the way to go if you're using Spring. Otherwise it's a big dependency.
  • Using ASM directly is a bit cumbersome.
  • Using Java Assist directly is clunky too.
  • Annovention is super lightweight and convenient. No maven integration yet.
  • Google reflections pulls in Google collections. Indexes everything and then is super fast.

The Classloader API doesn't have an "enumerate" method, because class loading is an "on-demand" activity -- you usually have thousands of classes in your classpath, only a fraction of which will ever be needed (the rt.jar alone is 48MB nowadays!).

So, even if you could enumerate all classes, this would be very time- and memory-consuming.

The simple approach is to list the concerned classes in a setup file (xml or whatever suits your fancy); if you want to do this automatically, restrict yourself to one JAR or one class directory.


If you want a really light weight (no dependencies, simple API, 15 kb jar file) and very fast solution, take a look at annotation-detector found at https://github.com/rmuller/infomas-asl

Disclaimer: I am the author.


You can find classes with any given annotation with ClassGraph, as well as searching for other criteria of interest, e.g. classes that implement a given interface. (Disclaimer, I am the author of ClassGraph.) ClassGraph can build an abstract representation of the entire class graph (all classes, annotations, methods, method parameters, and fields) in memory, for all classes on the classpath, or for classes in whitelisted packages, and you can query that class graph however you want. ClassGraph supports more classpath specification mechanisms and classloaders than any other scanner, and also works seamlessly with the new JPMS module system, so if you base your code on ClassGraph, your code will be maximally portable. See the API here.


And another solution is Google reflections.

Quick review:

  • Spring solution is the way to go if you're using Spring. Otherwise it's a big dependency.
  • Using ASM directly is a bit cumbersome.
  • Using Java Assist directly is clunky too.
  • Annovention is super lightweight and convenient. No maven integration yet.
  • Google reflections pulls in Google collections. Indexes everything and then is super fast.

With Spring you can also just write the following using AnnotationUtils class. i.e.:

Class<?> clazz = AnnotationUtils.findAnnotationDeclaringClass(Target.class, null);

For more details and all different methods check official docs: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html


Is it too late to answer. I would say, its better to go by Libraries like ClassPathScanningCandidateComponentProvider or like Scannotations

But even after somebody wants to try some hands on it with classLoader, I have written some on my own to print the annotations from classes in a package:

public class ElementScanner {

public void scanElements(){
    try {
    //Get the package name from configuration file
    String packageName = readConfig();

    //Load the classLoader which loads this class.
    ClassLoader classLoader = getClass().getClassLoader();

    //Change the package structure to directory structure
    String packagePath  = packageName.replace('.', '/');
    URL urls = classLoader.getResource(packagePath);

    //Get all the class files in the specified URL Path.
    File folder = new File(urls.getPath());
    File[] classes = folder.listFiles();

    int size = classes.length;
    List<Class<?>> classList = new ArrayList<Class<?>>();

    for(int i=0;i<size;i++){
        int index = classes[i].getName().indexOf(".");
        String className = classes[i].getName().substring(0, index);
        String classNamePath = packageName+"."+className;
        Class<?> repoClass;
        repoClass = Class.forName(classNamePath);
        Annotation[] annotations = repoClass.getAnnotations();
        for(int j =0;j<annotations.length;j++){
            System.out.println("Annotation in class "+repoClass.getName()+ " is "+annotations[j].annotationType().getName());
        }
        classList.add(repoClass);
    }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

/**
 * Unmarshall the configuration file
 * @return
 */
public String readConfig(){
    try{
        URL url = getClass().getClassLoader().getResource("WEB-INF/config.xml");
        JAXBContext jContext = JAXBContext.newInstance(RepositoryConfig.class);
         Unmarshaller um =  jContext.createUnmarshaller();
         RepositoryConfig rc = (RepositoryConfig) um.unmarshal(new File(url.getFile()));
         return rc.getRepository().getPackageName();
        }catch(Exception e){
            e.printStackTrace();
        }
    return null;

}
}

And in config File, you put the package name and unmarshall it to a class .


The Classloader API doesn't have an "enumerate" method, because class loading is an "on-demand" activity -- you usually have thousands of classes in your classpath, only a fraction of which will ever be needed (the rt.jar alone is 48MB nowadays!).

So, even if you could enumerate all classes, this would be very time- and memory-consuming.

The simple approach is to list the concerned classes in a setup file (xml or whatever suits your fancy); if you want to do this automatically, restrict yourself to one JAR or one class directory.


Google Reflections seems to be much faster than Spring. Found this feature request that adresses this difference: http://www.opensaga.org/jira/browse/OS-738

This is a reason to use Reflections as startup time of my application is really important during development. Reflections seems also to be very easy to use for my use case (find all implementers of an interface).


With Spring you can also just write the following using AnnotationUtils class. i.e.:

Class<?> clazz = AnnotationUtils.findAnnotationDeclaringClass(Target.class, null);

For more details and all different methods check official docs: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html


The Classloader API doesn't have an "enumerate" method, because class loading is an "on-demand" activity -- you usually have thousands of classes in your classpath, only a fraction of which will ever be needed (the rt.jar alone is 48MB nowadays!).

So, even if you could enumerate all classes, this would be very time- and memory-consuming.

The simple approach is to list the concerned classes in a setup file (xml or whatever suits your fancy); if you want to do this automatically, restrict yourself to one JAR or one class directory.


If you're looking for an alternative to reflections I'd like to recommend Panda Utilities - AnnotationsScanner. It's a Guava-free (Guava has ~3MB, Panda Utilities has ~200kb) scanner based on the reflections library source code.

It's also dedicated for future-based searches. If you'd like to scan multiple times included sources or even provide an API, which allows someone scanning current classpath, AnnotationsScannerProcess caches all fetched ClassFiles, so it's really fast.

Simple example of AnnotationsScanner usage:

AnnotationsScanner scanner = AnnotationsScanner.createScanner()
        .includeSources(ExampleApplication.class)
        .build();

AnnotationsScannerProcess process = scanner.createWorker()
        .addDefaultProjectFilters("net.dzikoysk")
        .fetch();

Set<Class<?>> classes = process.createSelector()
        .selectTypesAnnotatedWith(AnnotationTest.class);

If you want a really light weight (no dependencies, simple API, 15 kb jar file) and very fast solution, take a look at annotation-detector found at https://github.com/rmuller/infomas-asl

Disclaimer: I am the author.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to annotations

How to inject a Map using the @Value Spring Annotation? intellij incorrectly saying no beans of type found for autowired repository @Autowired - No qualifying bean of type found for dependency Difference between @Before, @BeforeClass, @BeforeEach and @BeforeAll Can't find @Nullable inside javax.annotation.* Name attribute in @Entity and @Table Get rid of "The value for annotation attribute must be a constant expression" message @Value annotation type casting to Integer from String What does -> mean in Python function definitions? @Nullable annotation usage

Examples related to classloader

Caused By: java.lang.NoClassDefFoundError: org/apache/log4j/Logger How to get names of classes inside a jar file? How do I put all required JAR files in a library folder inside the final JAR file with Maven? Dealing with "Xerces hell" in Java/Maven? What is the difference between Class.getResource() and ClassLoader.getResource()? How to use ClassLoader.getResources() correctly? this.getClass().getClassLoader().getResource("...") and NullPointerException Load properties file in JAR? Difference between thread's context class loader and normal classloader URL to load resources from the classpath in Java