How to use custom annotation processor with Maven 2? - java

In our enterprise application we are seeking a dynamic way to collect data from our Java classes. We created a custom annotation interface (#interface) with a name property. We would like to collect the value of this property from all annotated classes.
I managed to create an AnnotationProcessorFactory and an AnnotationProcessor for the custom annotation. Since we are using Maven 2, I added the following to the plugins in the pom.xml of the main project.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.0-alpha-5</version>
<configuration>
<factory>our.company.api.component.lister.ComponentAnnotationProcessFactory</factory>
</configuration>
</plugin>
This resides in the main project which has several sub-projects. The factory and the custom processor are in one of these sub-projects. The custom annotations are scattered through all of the sub-projects that is why I put the plugin in the pom.xml of the main project.
The problem is when I issue the mvn apt:process command I got a warning about the annotations without processors and our custom annotation is among them. I assume this means that the plugin cannot find the factory class.
What should I do so the plugin could find the factory and the processor file?
EDIT:
The project hierarchy is very simple:
main_project
|-sub_project1
|...
|-sub_projectn
The plugin is in the pom.xml of the main_project. Just assume that the factory and processor are in sub_project1 and the custom annotations are in sub_project2, sub_project3, ..., sub_projectn

Two things to check:
Make sure that the main_project (or the plugin) depends on the project which contains your ComponentAnnotationProcessFactory.
The <factory> configuration tag of the Apt Maven Plugin did not work for me but the plugin finds the factory class if its fully qualified name is in the META-INF/services/com.sun.mirror.apt.AnnotationProcessorFactory file. (See the documentation of apt for the details.)
A better approach is using the annotation processing features of JDK 6 (instead of the Maven Apt Plugin) since it does not require the com.sun package and the tools.jar from the lib folder of the JDK.
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<annotationProcessors>
<annotationProcessor>
com.example.annotationprocessor.Processor
</annotationProcessor>
</annotationProcessors>
</configuration>
</plugin>
</plugins>
</build>
Further references:
Annotation Processing Tool in the The Java Specialists' Newsletter
What is the default annotation processors discovery process?

Related

How can I make the exec-maven-plugin goal be invoked with the Maven package phase? [duplicate]

This is a snippet of my pom file.
....
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
......
</configuration>
</execution>
</executions>
</plugin>
</plugins>
...
I use it successfully with the command
mvn install
But, when I try to enclose it into the "pluginManagement" tag, the maven-dependency-plugin stops working when I launch the install goal.
Why does the "pluginManagement" tag change the build behavior? Or should I use another goal or option?
You still need to add
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
</plugin>
</plugins>
in your build, because pluginManagement is only a way to share the same plugin configuration across all your project modules.
From Maven documentation:
pluginManagement: is an element that is seen along side plugins. Plugin Management contains plugin elements in much the same way, except that rather than configuring plugin information for this particular project build, it is intended to configure project builds that inherit from this one. However, this only configures plugins that are actually referenced within the plugins element in the children. The children have every right to override pluginManagement definitions.
The difference between <pluginManagement/> and <plugins/> is that a <plugin/> under:
<pluginManagement/> defines the settings for plugins that will be inherited by modules in your build. This is great for cases where you have a parent pom file and would like to avoid having to copy the same code for the configuration of the plugin over to each of these modules.
<plugins/> is a section for the actual invocation of the plugins. It may or may not be inherited from a <pluginManagement/>.
You don't need to have a <pluginManagement/> in your project, if it's not a parent POM. However, if it's a parent pom, then in the child's pom, you need to have a declaration like:
<plugins>
<plugin>
<groupId>com.foo</groupId>
<artifactId>bar-plugin</artifactId>
</plugin>
</plugins>
Notice how you aren't defining any configuration. You can inherit it from the parent, unless you need to further adjust your invocation as per the child project's needs.
For more specific information, you can check:
The Maven pom.xml reference: Plugins
The Maven pom.xml reference: Plugin Management
You use pluginManagement in a parent pom to configure it in case any child pom wants to use it, but not every child plugin wants to use it. An example can be that your super pom defines some options for the maven Javadoc plugin.
Not each child pom might want to use Javadoc, so you define those defaults in a pluginManagement section. The child pom that wants to use the Javadoc plugin, just defines a plugin section and will inherit the configuration from the pluginManagement definition in the parent pom.
pluginManagement: is an element that is seen along side plugins. Plugin Management contains plugin elements in much the same way, except that rather than configuring plugin information for this particular project build, it is intended to configure project builds that inherit from this one. However, this only configures plugins that are actually referenced within the plugins element in the children. The children have every right to override pluginManagement definitions.
From http://maven.apache.org/pom.html#Plugin%5FManagement
Copied from :
Maven2 - problem with pluginManagement and parent-child relationship
<pluginManagement> just like <dependencyManagement> are both used to share only the configuration between a parent and it's sub-modules.
For that we define the dependencie's and plugin's common configurations in the parent project and then we only have to declare the dependency/plugin in the sub-modules to use it, without having to define a configuration for it (i.e version or execution, goals, etc). Though this does not prevent us from overriding the configuration in the submodule.
In contrast <dependencies> and <plugins> are inherited along with their configurations and should not be redeclared in the sub-modules, otherwise a conflict would occur.

Maven: how configure javadoc to generate all the private and package too

I am working with Maven 3.6.3, for a project based in one module, about the generation of the javadoc in the pom.xml file I have:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven.javadoc.plugin.version}</version>
<configuration>
<source>${jdk.version}</source>
</configuration>
</plugin>
Where maven.javadoc.plugin.version is 3.2.0.
The plugin works how is expected:
it generates by default all the public and protected methods and classes
Now, for developing purposes I need include all about the private and package (methods, classes) too. What is the correct extra configuration?. It is possible in Gradle, so I am assuming it is possible in Maven too.
Add
<show>private</show>
to your <configuration/>.

Integrate annotation processor into the same project

Is it possible to use annotation processor in the same project where it is defined?
Example:
src/
MyAnnotation.java
path_to_MyAnnotationProcessor.MyAnnotationProcessor.java
other classes
resources
META-INF/services/javax.annotation.processing.Processor
pom
when I will run mvn clean install, I will expect that my processor will process classes annotated with MyAnnotation.
I don`t want to import already compiled processor from another lib, I just want to use it once I defined it in my src.
For now, I get error:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.6.1:compile (default-compile) on project my-project: Compilation failure
[ERROR] Annotation processor 'path_to_MyAnnotationProcessor' not found
part of pom.xml, where I ref. to my processors:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.plugin.compiler}</version>
<configuration>
<source>${version.java}</source>
<target>${version.java}</target>
<annotationProcessors>
<proc>path_to_MyAnnotationProcessor.MyAnnotationProcessor</proc>
</annotationProcessors>
</configuration>
</plugin>
Thanks to everybody, especially to #Stefan Ferstl and #yegodm. The solution came from yegodm is:
"One way is two have two modules in the same project. One module would define annotations and processor. Another would have it as a dependency to establish build order."
The easiest way to solve this problem is convert your project into a multi-module project where the annotation processor is in its own module. Having a different module for the annotation processor, you could use the quite new <annotationProcessorPaths> option to define the annotation processor via groupId/artifactId.
The module using the annotation processor might need a dependency to the annotation processor module to get it built first.
Note: In a previous version of this answer I described an additional way to solve this problem, which apparently didn't work out of the box. That part has been deleted.
You could compile your processor earlier with a separate compiler execution.
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>compile-generator</id>
<phase>generate-sources</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<includes>
<include>com/example/YourProcessor.java</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
I've tested this, and it works - the processor does get invoked later during the actual compile phase.
If you precompile some other classes from the same project too, then you could directly reference and use them in the processor. That could be useful.

How to package a message-driven bean using Maven?

I want to package a message-driven bean using Maven. The bean has various dependencies (external libraries) that should be packaged with it. In the end, the resulting package should be deployed on an application server (such as Wildfly).
I tried to create multi-module Maven project where I have a module with "ear" packaging that depends on the actual message-driven bean module which uses "jar" packaging (I also tried "ejb" here). However, when the message-driven bean is called it is not able to acccess its dependencies (no NoClassDefFoundError).
The following change to my "ear" pom fixed this issue because the dependencies are now accessible to the message-driven bean.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<defaultLibBundleDir>lib</defaultLibBundleDir>
</configuration>
</plugin>
</plugins>
</build>
While it basically works now, I feel like I am doing something wrong. Do I really need to change my pom like this? If I have to place the dependencies in the lib directory, why is Maven not doing this by default when building an EAR file.
the EAR/lib folder is the default folder for libraries and every *.jar file inside this folder is automatically loaded by the ear classloader (Java EE 7 Specification)
i think that the EAR/lib folder is come in later specifications of java ee and the maven ear plugin is not updated to this "java ee defaults".
with "defaultLibBundleDir" in maven-ear-plugin all the transitive dependencies are put inside this declared folder. the second is that inside the application.xml folder maven is configuring the "library-directory" element. and this is not required because the "lib" folder is default loaded with the ear classloader.
and this can solved by the setting the maven ear configuration libraryDirectoryMode to NONE
i think it is also best practice to use the fileNameMapping to no-version configuration. this removes the maven versions out of the file names. the maven version is also inside the jar/META-INF/MANIFEST.MF
this is for the jndi name of the modules because the module name came from the jar/war name without the file ending.
your configuration whould look like this:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<defaultLibBundleDir>lib</defaultLibBundleDir>
<libraryDirectoryMode>NONE</libraryDirectoryMode>
<fileNameMapping>no-version</fileNameMapping>
</configuration>
</plugin>
</plugins>
</build>

default maven compiler setting

Right now, I'm writing a small java application by my own, with few maven pom.xml files. I want to make all my maven packages to compile with jdk 1.6, and I can't find a good way to do it without manually setting it on every single POMs - I'm sick of copy-and-pasting
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
in every single pom.xml file I generate.
Is there a simpler way to resolve this issue?
Create a pom-only (<packaging>pom</packaging>) project that has the compiler settings (and any other default settings) you want. You give treat it like any other project (release it; deploy it to your Maven repo, etc.).
Put a parent declaration at the top of your pom files:
<parent>
<groupId><!-- parent's group id --></groupId>
<artifactId><!-- parent's artifact id --></artifactId>
<version><!-- parent's version --></version>
</parent>
It doesn't help much if all you want to set is compiler settings. But if you find yourself configuring lots of plugins, reports and dependencies in the same way across project, you can create one parent to rule them all.
BTW - be careful about declaring dependencies and plugins in your parent pom file. Usually you'll want to favor dependencyManagement and pluginManagement. See the documentation for more details.
You could specify this plugin and configuration in your ~/.m2/settings.xml, which will then apply it to all projects.
However this has the downside of making your projects no longer portable - attempting to build the same code with the same pom.xml will fail on other machines that don't have the same settings.xml values as you.
I'm sick of copy-and-pasting
Yes, and you should use POM inheritance to avoid this and configure the maven-compiler-plugin in the parent POM.
Another option would be to use the solution suggested by #matt (and he nailed down pros and cons of the use of settings.xml).
In both cases, this is typically a setting that I like to check using the maven-enforcer-plugin and its requireJavaVersion rule that you would configure like this:
<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<id>enforce-versions</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireJavaVersion>
<version>1.6</version>
</requireJavaVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
[...]
</project>
But it can do more (like checking the maven version). Very useful.
I want to make all my maven packages to compile with jdk 1.6
If this is multi-module project just put these settings to top-level POM under pluginManagement.
If you have many independent project just copy-and-paste this configuration. Beware of "smart" solutions like setting this somewhere globally. Some day you will want to use different compiler settings for one or two of your projects and the nightmare will begin :-)
Remember...
Keep things as simple as possible, but no simpler.

Categories