26

I have a plain jane servlets web application, and some of my classes have the following annotations:

@Controller
@RequestMapping(name = "/blog/")
public class TestController {
..

}

Now when my servlet applications starts up, I would like to get a list of all classes that have the @Controller annotation, and then get the value of the @RequestMapping annotation and insert it in a dictionary.

How can I do this?

I'm using Guice and Guava also, but not sure if that has any annotation related helpers.

loyalflow
  • 14,275
  • 27
  • 107
  • 168
  • Why are you trying to access the annotations directly? Are you planning on doing something with them? Are you just wanting a list of the classes with those annotations? – Robert Oct 29 '12 at 19:49
  • I'm going to get the value of the requestmapping and insert them into a dicionary. – loyalflow Oct 29 '12 at 20:26
  • 1
    possible duplicate of [Scanning Java annotations at runtime](http://stackoverflow.com/questions/259140/scanning-java-annotations-at-runtime) – Adrian Ber Dec 23 '14 at 09:27

7 Answers7

42

You can use the Reflections library by giving it the package and Annotation you are looking for.

Reflections reflections = new Reflections("my.project.prefix");
Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(Controller.class);

for (Class<?> controller : annotated) {
    RequestMapping request = controller.getAnnotation(RequestMapping.class);
    String mapping = request.name();
}

Of course placing all your servlets in the same package makes this a little easier. Also you might want to look for the classes that have the RequestMapping annotation instead, since that is the one you are looking to get a value from.

Jacob Schoen
  • 14,034
  • 15
  • 82
  • 102
5

Scanning for annotations is very difficult. You actually have to process all classpath locations and try to find files that correspond to Java classes (*.class).

I strongly suggest to use a framework that provides such functionality. You could for example have a look at Scannotation.

chkal
  • 5,598
  • 21
  • 26
  • 2
    Very difficult??? I'd say it's [very simple](http://unixhelp.ed.ac.uk/CGI/man-cgi?find) when you know you CLASSPATH (what you normally do). But I agree that using a good tool is a good idea. – maaartinus Oct 29 '12 at 22:47
  • 2
    It is very difficult if you want to do it efficiently. Especially if you don't want to create Class instances for all classes on the classpath. – chkal Oct 30 '12 at 08:34
  • Scannotation is EOL and not maintained since 2008. – Lonzak Jun 16 '23 at 09:53
5

If you are using Spring,

It 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;
    }
swayamraina
  • 2,958
  • 26
  • 28
2

Try corn-cps

List<Class<?>> classes = CPScanner.scanClasses(new PackageNameFilter("net.sf.corn.cps.*"),new ClassFilter().appendAnnotation(Controller.class));
for(Class<?> clazz: classes){
   if(clazz.isAnnotationPresent(RequestMapping.class){
     //This is what you want
   }
}

Maven module dependency :

<dependency>
    <groupId>net.sf.corn</groupId>
    <artifactId>corn-cps</artifactId>
    <version>1.0.1</version>
</dependency>

visit the site https://sites.google.com/site/javacornproject/corn-cps for more information

Serhat
  • 222
  • 4
  • 2
2

The following code worked for me, the below example uses Java 11 and spring ClassPathScanningCandidateComponentProvider. The usage is to find all classes annotated with @XmlRootElement

public static void main(String[] args) throws ClassNotFoundException {
    var scanner = new ClassPathScanningCandidateComponentProvider(false);
    scanner.addIncludeFilter(new AnnotationTypeFilter(XmlRootElement.class));

    //you can loop here, for multiple packages
    var beans = scanner.findCandidateComponents("com.example");
    for (var bean : beans) {
        var className = bean.getBeanClassName();
        Class clazz = Class.forName(className);
        //creates initial JAXBContext for later usage
        //JaxbContextMapper.get(clazz);
        System.out.println(clazz.getName());
    }
}
Asanka Siriwardena
  • 871
  • 13
  • 18
-2

Instead of using reflection directly, you can make a lot easier for you by using AOP libraries from Google Guice. AOP is a common way for implementing cross-cutting concerns of an application, such as logging/tracing, transaction handling or permission checking.

You can read more about it here: https://github.com/google/guice/wiki/AOP

Deepak gupta
  • 109
  • 1
  • 5
-4

If you can get access of your .class files, then you may get the annotation using the class as below:

  RequestMapping reqMapping =  
                         TestController.class.getAnnotation(RequestMapping.class);
  String name = reqMapping.name(); //now name shoud have value as "/blog/"

Also please make sure, your classes are marked with RetentionPolicy as RUNTIME

  @Retention(RetentionPolicy.RUNTIME)
Yogendra Singh
  • 33,927
  • 6
  • 63
  • 73
  • 10
    The question was how to "get a list of all classes that have the @Controller annotation". Checking individual classes for the annotation is a completely different thing. – chkal Oct 30 '12 at 09:51