views:

63

answers:

4

I have a code generator that uses URLClassLoader to load classes on a specified path, scan them for annotations, and then using Reflection on the fields/methods, generate DTOs.

It works great, in the test app.

When I put it into the Maven MOJO, I suddenly lose the ability to see the javax.persistence.Entity annotations on the classes. It loads them, it can see all the fields, but the Entity annotation is no longer visible.

I am assuming this is something to do with Classpath issues - is it? Neither the test app (a main() function in the plugin itself) or the MOJO are part of the project that the scanned classes are from. But one works and the other doesn't.

I have a little bit of debug code that prints out all of the annotations on the class when it examines them, and in the non-running version it finds literally none.

Any ideas how I debug the problem/solve it?

A: 

Annotations have a persistence level associated with them. Some don't survive compile time (i.e. they are not put into the .class files.) Check to see that the ones you are referencing are not of this type.

Chris Nava
I referenced one specifically, which is Entity, and visible at runtime. In any case, I found the problem and will post a solution shortly.
Jason Maskell
+2  A: 

When you scan loaded class for annotations, you can't see the annotations which can't be found in classpath. That is, to read JPA's Entity annotation your code generator should have a JPA API in classpath (javax.persistence:persistence-api:1.0 in Maven).

However, if you use classloader to load external classes and scan them for annotations, you may face other problems with missed dependencies and execution of static initializers. May be, the better approach is to use bytecode manipulation libraries, such as ASM, to scan classes without loading them.

axtavt
A: 

I am assuming this is something to do with Classpath issues

My bet is that the persistence-api artifact is declared with a provided scope and isn't listed in the class path passed to the plugin. Can you confirm this?

Pascal Thivent
Actually that wasn't it. It was scoped in, the problem was the instantiation of the URLClassLoader.
Jason Maskell
@Jason Bet lost then :) Thanks for the feedback.
Pascal Thivent
+1  A: 

The problem turned out to be pretty simple, although I'm not sure why it worked fine in one case and not in another.

My URLClassLoader creation didn't specify a parent classloader. So, I assume it couldn't find anything. As soon as I used

loader = new URLClassLoader(classUrls, Thread.currentThread().getContextClassLoader());

for the classloader, it all started working just fine. I'm pretty ignorant when it comes to the ins and outs of classloaders, so this wasn't obvious. Especially since the example I was following didn't specify a parent either.

Jason Maskell