My experience while writing an annotation processor - part II
Earlier I shared the Java/JDK issues that I faced while writing an annotation processor. Today I am going to share my experience of using Maven. The issues have hardly anything to do with the annotation processor itself. If you are curious about what that annotation processor does, please refer to my earlier blog. Now, without wasting much time, let me describe the issues in the order in which I encountered them.
1. Which maven-jaxb-plugin to use?
Since my annotation processor reads and writes XML, I did not hesitate a moment to choose JAXB as part of my solution. Next I had to search for a Maven plugin for XJC, the JAXB code generator. When I googled for Maven JAXB plugin, it came up with multiple answers. Need-less-to-say, it was confusing. Knowing Kohsuke and the popularity of JAXB java.net project, I preferred their plugin as opposed to the one available in Maven repo.
2. Not able to pass a URL to maven-jaxb-plugin
Please refer to my posting in JAXB forum where I have raised this issue. Lack of this facility forced to maintain a copy of the schema document in my source tree. I hate such duplication.
3. Not able to specify compiler configuration differently for different phases
Obviously, my main source code tree (src/main) contains the annotation processor and other supporting code, and test source tree (src/test) is where I have the test cases to test the processor. I use auto-discovery of annotation processor by javac, which means if my processor is in javac's classpath, then javac invokes it automatically. Of course, I do not want my processor to be active when I am compiling the processor itself; I only want it to be used during test compilation. Since a previous successful compilation makes it available to javac to execute, I had to find a way to avoid annotation processing during main source code compilation. javac has an option -proc:none that fits my requirement. All I had to do is to use that option during compilation, but not use it during testCompilation goal of the maven-compiler-plugin. I was surprised to find that there is no straight forward way to configure maven-compiler-plugin differently for different phases. The compiler always has one configuration that it applies to all the phases. In addition to that, you can specify extra configurations that it applies when executing certain goal. My discussion in Maven User forum has not made much progress, except that I found a work around to my problem. Eventually, I configured the plugin like this:
< plugin> < groupId> org.apache.maven.plugins</groupId> < artifactId> maven-compiler-plugin</artifactId> < configuration> < compilerArgument> -proc:none</compilerArgument> </configuration> < executions> < execution> < id> run-annotation-processor-only</id> < phase> process-test-resources</phase> < goals> < goal> testCompile</goal> </goals> < configuration> < compilerArgument> -proc:only< /compilerArgument> </configuration> </execution> </executions> </plugin>
If you carefully look at it, you can see that the above pom would invoke the compiler-plugin three times in the following order to execute test phase:
1) compile goal - during compile phase, during which it uses -proc:none option.
2) testCompile goal - during process-test-resources, during which it uses -proc:only option.
3) testCompile goal - during test-compile phase, during which it uses same configuration as compile goal.
An excellent overview Maven's build life cycle and various phases that it comprises of is available here.
5. Maven not printing information printed using Messager
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. Debugging javac launched via Maven, I gather some more information and have sent a mail to Maven User forum. Let's see what they respond. Until then, I am afraid, one has to use System.out if they want their annotation processor output to be visible in console while using Maven.
Other than these issues, I had a pleasant experience of using Maven. I am not a maven expert - I am just starting. I have earlier used Maven (remember being a GlassFish developer, I execute maven scripts every day), but those were maven1 scripts that someone else has written, and I just run them. This was the first time I wrote maven2 scripts and used them. I do have a reasonable amount of experience of using build tools like Make, Ant, etc. Make is still my favorite tool - I used GNU Make quite a lot in the past when I used to work primarily in C++. I am particular interested in Maven because it addresses a key issue in software development - that of dependency management. It's a bill of materials issue in software well addressed by Maven. I don't think I need to praise Maven any more as lots of people have started to use it and we at GlassFish project have started using it in very actively. Here are a couple of thoughts:
1. I think any new addition to the maven central repository needs to be carefully evaluated. It would be better to have a staging (or beta) repository where experimental stuff can go. Only when an artifact is popular or standardized, it should find its way to the central repository. I know there is a process in place, but I still think the repository has far too many stuff out there than what it should have at this point of time.
2. Having wrappers(plugins) for underlying tools has its merits and demerits. e.g. underlying XJC plugin allows me to pass a URL, where as the maven-jaxb-plugin does not. Would it be better to just let people invoke the underlying tool directly, just as they did in Make? Or is that out of fashion now?
I look forward to your comments. Thanks for reading.More blogs about Maven2...