3

I'm developing a small application that passes messages around, which are POJOs. I'd like to construct a registry of the types of messages that can be handled. I originally planned to stick them in an enumerated type as follows.

public enum Message
{
    INIT( InitMessage.class, "init" ),
    REFRESH( RefreshMessage.class, "refresh" );

    private Message( Class<?> messageClass, String messageCode )
    // etc..
}

I don't like this approach, as I have to maintain a central enumerated type to manage the allowed classes. I'd prefer to instead annotate the POJOs.

@MessageDefinition( "init" )
public class InitMessage
{
    // .. some properties with appropriate getters and setters
}

I checked out the Tomcat source from Subversion, and even with the help of an IDE, it was taking me a very, very long time to wade through the levels of abstraction and get to some gutsy code showing me how it scans the classes in a webapp searching for annotated classes to register @WebServlet, @WebListener, etc. Even more off-putting was the fact that I could only really see references to those annotations in test classes.

My question is how do annotation driven frameworks scan for annotations? It's hard to know which classes you're hoping to scan, even moreso before they've been loaded by the classloader. I was thinking the approach might be to look for all files that end in a .class extension, load them and check for annotations. However, this approach sounds pretty nasty.

So I guess it boils down to:

  • how does Tomcat find annotated-classes? (or any other frameworks you're familiar with)
  • if Tomcat's (or the framework you mentioned above's) approach sucks, how would you do it?
  • is there a better way that I should architect this overall?

Note: Scan the classpath for classes with custom annotation is great, but I'd love to do it with standard Java 7 if possible.

Update: Reflections is not suitable. It has a tonne of dependencies, and to make things worse, it relies on old versions of libraries - in particular one that takes pride in deprecating dozens of features every release, and releasing rapidly.

I'm thinking about following this guide and using ASM if possible: http://bill.burkecentral.com/2008/01/14/scanning-java-annotations-at-runtime/

Community
  • 1
  • 1
jr.
  • 1,699
  • 14
  • 31
  • 1
    Take a look at the [Reflections](http://code.google.com/p/reflections/) library - it does quite a lot of the work for you. Doing this by hand is really quite tricky... – Boris the Spider Nov 10 '13 at 10:52
  • @BoristheSpider - I had both this suggestion and corn-cps in mind. If I don't get an answer that satisfies the "no external dependencies" addendum within a few days, perhaps you can add this comment as an answer, making a stronger note of the fact that it is ridiculously hard to roll code to do this yourself and I'll give you that magical green tick. Thanks for your help. :) I'll get familiar with Reflections in the mean time. – jr. Nov 10 '13 at 12:01
  • 1
    @studro take a look at http://stackoverflow.com/questions/259140/scanning-java-annotations-at-runtime – Dev Blanked Nov 10 '13 at 12:05
  • @DevBlanked - I didn't see this question - thanks for pointing it out. Feel free to vote to close this one. – jr. Nov 10 '13 at 12:18
  • 1
    You can also do a lot with annotations at compile time. It's called "Annotion Processing" and can be done with the Mirror API (similiar to Reflections but at compile time, including more type information etc.). It's not for every usecase and I don't know how widley it's used by fameworks. I'd say this is the prefered standard java way and cleaner than analyzing bytecode if compile time processing is an option. – kapex Nov 10 '13 at 18:32

1 Answers1

2

Tomcat scans for annotations using a cut-down (so only the bits Tomcat needs are present) and package renamed (so it doesn't clash if the web app ships with BCEL as well) version of Apache Commons BCEL. It looks for every .class file, reads the byte code and extracts the annotations.

For the details, you can look at the source code. Start at line 1130 of this file: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java?annotate=1537835

The other popular library for doing this sort of thing is ASM.

Mark Thomas
  • 16,339
  • 1
  • 39
  • 60