Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build a list of classes annotated with my custom annotation?

I want to get a complete list of classes in the application which are annotated with @Custom annotation. What is the best mechanism for this operation?

ps. For example, how JAX-RS implementations find all classes that are annotated with @Path? I would like to use the same mechanism.

like image 570
yegor256 Avatar asked Nov 05 '10 15:11

yegor256


People also ask

What is @interface annotation in Java?

@interface is used to create your own (custom) Java annotations. Annotations are defined in their own file, just like a Java class or interface. Here is custom Java annotation example: @interface MyAnnotation { String value(); String name(); int age(); String[] newNames(); }

How do you inherit annotations?

Annotations, just like methods or fields, can be inherited between class hierarchies. If an annotation declaration is marked with @Inherited , then a class that extends another class with this annotation can inherit it. The annotation can be overridden in case the child class has the annotation.


6 Answers

Usually this is done using the process called classpath scanning. In general class loaders do not allow for scanning through all the classes on the classpath. But usually the only used class loader is UrlClassLoader from which we can retrieve the list of directories and jar files (see getURLs) and open them one by one to list available classes.

This approach is implemented by libraries like Scannotation and Reflections.

Another approach is to use Java Pluggable Annotation Processing API to write annotation processor which will collect all annotated classes at compile time and build the index file for runtime use.

The above mechanism is implemented in ClassIndex library.

Using classpath scanning is usually two orders of magnitude slower than compile-time indexing. See this benchmark.

like image 145
Sławek Avatar answered Oct 05 '22 23:10

Sławek


I know this is an old question, but I ran across it in my own search for classpath scanning and found another good answer, so I'm adding it here.

Google Guava has a ClassPath object that provides "best effort" classpath scanning (which is all any classpath scanning utility offers, really). Since Guava is a widely-adopted, carefully-maintained utility library, this is a great option for projects that either (a) are already using Guava, or (b) need a stable library they can rely on for classpath scanning.

like image 40
sigpwned Avatar answered Oct 06 '22 00:10

sigpwned


You should take a look at Scannotation.

like image 36
keuleJ Avatar answered Oct 06 '22 00:10

keuleJ


classindex is a compile-time annotation scanning library, implemented using an annotation processor.

like image 21
snorbi Avatar answered Oct 06 '22 00:10

snorbi


You could try my library FastClasspathScanner:

List<String> classNames = new FastClassPathScanner("com.mypackage")
    .scan()
    .getNamesOfClassesWithAnnotation(Custom.class);
like image 33
Luke Hutchison Avatar answered Oct 05 '22 23:10

Luke Hutchison


As you probably know by now, Java has no way to enumerate all packages or the classes in each package. So you have to do it the "hard" way. Options:

  1. Use a tool like grep to search for the annotation. Advantage: Fast, simple. Drawbacks: Might return false positives (like classes where the annotation is commented out).

  2. Compile the code and process the result with javap. That works on the bytecode level[*]. It gives you accurate results but the output of javap isn't really meant for automatic processing.

  3. Use a bytecode library like ASM. Not for the faint of heart but it allows you to access other data as well (like implemented interfaces, fields, etc) in relation to the annotation.

  4. Last option: Eclipse uses its own Java compiler which can build an AST from Java code (even if the code doesn't compile). Advantage over ASM: You get a model for Java code for free. Makes certain operations more simple. No so easy to set up, though. See my blog for an example.

[*]: The annotation must have Retention.RUNTIME for this to work.

like image 25
Aaron Digulla Avatar answered Oct 06 '22 01:10

Aaron Digulla