The Source for Java Technology Collaboration
User: Password:



 Sahoo

Sahoo's Blog

My experience while writing an annotation processor - part I

Posted by ss141213 on November 27, 2007 at 09:40 AM | Comments (5)

Recently I was writing an annotation processor that would generate a persistence.xml file when I compile my JPA entity classes. If you are a Java Persistence API user, then you may actually be interested in that annotation processor. OK, enough of shameless self promotion. Coming to the issue I want to discuss in this blog... While writing the annotation processor, certain things did not happen as per my expectation. I will share them with you so that you won't waste time as I did. All those issues are generic in nature.

1. Thread.getContextClassLoader is not the class loader you want to use
In my annotation processor's process() method, I wanted to load a resource (say) foo/bar.xml which is part of the same jar which houses the annotation processor itself. So, I wrote:
Thread.currentThread().getContextClassLoader().getResourceAsStream("foo/bar.xml").
This returns null. So, I had to change my code to:
this.getClass().getClassLoader().getResourceAsStream("foo/bar.xml").
May be it is by design, in that case I don't understand the rationale. Why the class loader of the thread executing my annotation processor is not able to load a resource which is part of a jar that is passed as -classpath to javac. More over, it's the same jar from where the annotation processor has been loaded!

2. Filer.getResource(SOURCE_PATH...) throws NPE if -sourcepath not specified
In my annotation processor, I wanted to locate a file in source path, so I wrote the following code:
FileObject fo = processingEnv.getFiler().getResource(StandardLocation.SOURCE_PATH, "", "META-INF/persistence.xml");
It throws NullPointerException if I do not specify -sourcepath option while invoking javac. I have two questions:
1) Is "." not the default value for source search path?
2) Instead of throwing an IOException as per the javadocs of getResource, why is it throwing an NPE?
The stack trace is available in the unanswered forum posting of mine.

3. Filer.createResource ignores directory part of relative URI
My annotation processor tries to create an output file called META-INF/persistence.xml in the classes output directory (i.e. -d option to javac). So, I wrote following code:
final FileObject fo = processingEnv.getFiler().createResource(
StandardLocation.CLASS_OUTPUT, // -d option to javac
"",
"META-INF/persistence.xml",
null);

This works as long as I pass -d option to javac. e.g., if I invoke:
javac -d . Foo.java
it creates ./META-INF/persistence.xml. But, if I invoke
javac Foo.java
it creates ./persistence.xml! Where is my META-INF directory gone?

4. javac does not print enough information about an exception
I am very surprised to find that javac does not print the stack trace of exceptions that are thrown by annotation processors, not even in -verbose mode. Nor does it tell me which annotation processor threw the exception. Given below is an example of javac output in -verbose mode:
Round 1:
input files: {sahoo.EmploymentRecord}
annotations: [javax.persistence.Embeddable]
last round: false
error: Exception thrown while constructing Processor object: java.lang.NullPointerException

My question in the JDK forum has fallen into deaf ears.
Of course, the work around is a simple one - just catch all exceptions in your code and log them before re-throwing. But, I think I should not have to do this.

5. Not able to debug annotation processor
It's my lack of knowledge. Until now, I never had to debug javac. Now that I am writing some code that gets called as part of javac, I felt the need to debug javac. I have still not found a way to do so. I tried passing the standard JVM debug options using "-J" option, but in vain. If you know how to attach a debugger to javac, please let me know. I use NetBeans IDE.

6. Maven not printing information printed using Messager
This is more of an issue about how maven-javac-plugin interacts with javac. I am using Maven 2.0.7. In my code, I use Messager object to report progress of my annotation processor. Those messages appear in my console when I run javac directly, but they appear nowhere when maven invokes the compiler using maven-compiler-plugin. Finally, I switched to using System.out, not a bright idea as it defeats the purpose of a Messager in the first place, but I just could not afford the extra time required to get to the root cause.

As usual, your comments are most welcome. Next time, I shall share the issues that I faced while using Maven.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • For discussions of annotation processing, try the annotation processing forum.

    Posted by: jddarcy on November 27, 2007 at 12:42 PM

  • Beware that your Classloading mechanism will not work properly in all environments (J2EE app servers with complex EAR files) when using the changes you made


    Thread.currentThread().getContextClassLoader().getResourceAsStream("foo/bar.xml").
    This returns null. So, I had to change my code to:
    this.getClass().getClassLoader().getResourceAsStream("foo/bar.xml").


    Instead you should use the Thread.currentThread().getContextClassLoader() and fall back to getClass().getClassLoader() only as a last resort. If you have an EAR structure such as:


    Some.ear
    lib/annotation-processor.jar
    Some.war
    WEB-INF/classes/foo/bar.xml


    The non-context classloading approach will fail.

    Posted by: craig514miller on November 27, 2007 at 01:14 PM

  • The new code will always work because I am using the class loader that loaded my annotation processor and the resource I am loading is available in the same jar as that of the annotation processor. If I were to load resource from some other place, then I might face other issues as you pointed out.

    Secondly, this code runs as part of javac, I don't see where Java EE ear is coming to picture.

    Sahoo

    Posted by: ss141213 on November 27, 2007 at 09:48 PM

  • Sahoo,

    If you post the debugging question in the forum, I'll answer it there. Yes there is an answer.

    Bruce

    Posted by: brucechapman on November 28, 2007 at 03:40 PM

  • Sahoo, if the forum doesn't satisfy, drop bugs into Sun's bug parade. It might take until JDK7 to fix them, but they'll get fixed eventually.

    Posted by: dwalend on November 29, 2007 at 05:44 AM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds