Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot load resources in Annotation Processor (Not on classpath)

I have an annotation processor which shall generate a enumeration with the keys defined by getter methods of an interface.

The interface resides in

MyProject/src/main/java/my.package.MyInterfaces.java.

I want to validate the properties files which reside in MyProject/src/main/resources/META-INF/resource-bundle/ if they do contain the keys defined in the generated enum.

My problem is that the properties files are not available via the classloader of the processor or via Filer.getResource(...).

  • How can I make the source or classpath of this project available to the processor, so that I can load the properties files ?

  • Now I have only the resources within the jar where the processor resides available. I did try to define -classpath and/or -sourcepath via eclipse Project/Properties/Java compiler/Annotation processing/Processor options but it did not work out.

Has anyone faced an issue like this, and can anyone give me a clue as to how I can make the resources available for the processor?

I do have the maven structure but do not use maven, because of old dependencies within the application. So maven is now not an option for me.

Eclipse 3.6 Helios Seems that StandardLocation.SOURCE_PATH and StandardLocation.CLASS_PATH are not implemented in Filer#getResource(), so writing generated source or class files to SOURCE_PATH or CLASS_PATH seems not be possible, also accessing any files on SOURCE_PATH and CLASS_PATH*

Thanks.

like image 463
CCHET Avatar asked Aug 07 '13 11:08

CCHET


1 Answers

The issue is the ClassLoader that is bound to the current thread (Thread.currentThread().getContextClassLoader()) is not a URLClassLoader when Processor#process is called. It appears to be a restricted class loader that does not allowing loading resources. This happens with javac, eclipse compiler, maven compiler, etc.

Luckily your processor class will have an appropriate ClassLoader bound to it (ie getClass().getClassLoader()).

The problem is most utilities expect the correct ClassLoader to be bound to the thread (most notably the ServiceLoader and ResourceBundles).

Thus there is a work around. When your Processor executes you can rebind the ClassLoader to the current thread:

@Override
public boolean process(
        Set<? extends TypeElement> annotations,
        RoundEnvironment roundEnv) {

    Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
    //...
}

EDIT:

I have feeling a large amount of people are having the problem of resources that are in src/main/resources with Eclipse not loading them using the annotation processor Filer (throws an exception).

And indeed it is a well known issue that Eclipse will not load target/classes resources. The classpath hack I showed above may or may not work and was more for other libraries being used by the processor (as in they are already compiled with the resources).

The solution (if it could be called that) is to load the files like they are normal files. This requires guessing the project structure with some hacks.

OR

You can tell Eclipse users just to put the resources in src/main/java.

like image 92
Adam Gent Avatar answered Nov 17 '22 01:11

Adam Gent