38

I need to run an annotation processor on my project's sources. The annotation processor should not become a transitive dependency of the project since it's only needed for annotation processing and nothing else.

Here is the complete (non-working) test pom I use for this:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>test</groupId>
  <artifactId>test</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Test annotations</name>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <hibernate-jpamodelgen.version>1.2.0.Final</hibernate-jpamodelgen.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>javax</groupId>
      <artifactId>javaee-api</artifactId>
      <version>6.0</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.0</version>
        <configuration>
          <annotationProcessors>
            <annotationProcessor>
              org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</annotationProcessor>
          </annotationProcessors>
          <debug>true</debug>
          <optimize>true</optimize>
          <source>1.6</source>
          <target>1.6</target>
          <compilerArguments>
            <AaddGeneratedAnnotation>true</AaddGeneratedAnnotation>
            <Adebug>true</Adebug>
          </compilerArguments>
        </configuration>
        <dependencies>
          <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-jpamodelgen</artifactId>
            <version>${hibernate-jpamodelgen.version}</version>
          </dependency>
        </dependencies>
      </plugin>
    </plugins>
  </build>
</project>

I explicitly defined org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor as an annotation processor in the plugin configuration for tests and I know it shouldn't be required.

The problem I'm encountering is that the hibernate-jpamodelgen dependency is not added to the compiler classpath so the annotation processor is not found and the build fails.

As per this answer, I tried adding the dependency as a build extension (not sure I understand what those are supposed to be!) like so:

<extensions>
  <extension>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-jpamodelgen</artifactId>
    <version>${hibernate-jpamodelgen.version}</version>
  </extension>
</extensions>

This also doesn't add hibernate-jpamodelgen to the compiler classpath.

The only thing I found which works so far is adding the dependency to the project in the <dependencies> section. This has the unfortunate side-effect of adding hibernate-jpamodelgen as a transitive dependency afterwards which I want to avoid.

My previous working setup uses the maven-processor-plugin plugin to achieve what I want. However, this plugin is not supported by eclipse m2e and the latest version of the maven-compiler-plugin now handles multiple compiler arguments properly so I'd rather use the latter.

Community
  • 1
  • 1
bernie
  • 9,820
  • 5
  • 62
  • 92

7 Answers7

44

The annotationProcessorPaths option can be used in recent versions of the Maven compiler plug-in:

<pluginManagement>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.6.1</version>
            <configuration>
                <annotationProcessorPaths>
                    <annotationProcessorPath>
                        <groupId>org.hibernate</groupId>
                        <artifactId>hibernate-jpamodelgen</artifactId>
                        <version>5.2.6.Final</version>
                    </annotationProcessorPath>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</pluginManagement>

That way the processor is separated from the actual project dependencies. This option is also picked up by the Eclipse M2E plug-in if annotation processing is enabled for the project.

Gunnar
  • 18,095
  • 1
  • 53
  • 73
  • For some reason, it does not help. Once I add annotation processor as dependency (compile time) it works as expected. However, it is just old way to resolve the issue. Am I correct that adding artifact in `` does not require add that artifact in dependency section also? Any idea what am I missing? – sphinks Sep 16 '22 at 13:10
28

Add the dependency as an optional dependency (<optional>true</optional>). This will add the dependency under compilation, but will prevent it for being a transitive dependency:

<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-jpamodelgen</artifactId>
  <version>${hibernate-jpamodelgen.version}</version>
  <optional>true</optional>
</dependency>

If you're creating an artifact in this module with all your dependencies in it (like a .war), you may use the <scope>provided</scope> instead. This both prevents the dependency to be transitive and to be included in the artifact the module produces.

Jin Kwon
  • 20,295
  • 14
  • 115
  • 184
Aleksander Blomskøld
  • 18,374
  • 9
  • 76
  • 82
  • Thanks this works! However, based on the Maven doc regarding scopes, this doesn't seem like the intended usage of `optional` and `provided`. I'll accept your answer (hey it works!) if no "better" answer comes up. – bernie Jan 14 '13 at 17:07
  • Also, it looks like `provided` will always do the right thing whereas `optional` won't with `war` packaging. Do you see any case where `provided` would fail? – bernie Jan 14 '13 at 17:10
  • 1
    Nope, I guess provided will always do the right thing for you. I also agree that it doesn't sounds right with "provided", but I guess you wont find any better solution. – Aleksander Blomskøld Jan 14 '13 at 18:36
  • 3
    "Optional" just means it's not required by other projects which depend on this one. If they want it, they have to declare it explicitly. Usually other projects won't want your annotation processors, so it's optional (not required). For annotation processors to work, javac finds them on the compile-time classpath, which is the compile scope in maven. "provided" is a special scope for some plugins which package/bundle compile-time dependencies. They are often confused, but it's easier if you think about what other projects need from your project, when they depend on yours. – Christopher Mar 24 '16 at 23:17
  • 1
    In version 3.5 of the Maven compiler plug-in a new "annotationProcessorPaths" option was introduced. I recommend to use that (see my answer below) instead of exposing the processor JAR as a project dependency. – Gunnar Jan 21 '17 at 09:45
  • 1
    Something to keep in mind with "annotationProcessorPaths" is that it might be unintentionally overriding processors from a parent POM. `` in the child POM makes sure that the already configured ones are preserved. – Frettman Dec 25 '21 at 12:54
12

For JDK 10 I really had to go a bit crazy to get it to work, Hoping someone finds this useful

<jaxb.version>2.3.0</jaxb.version>
<maven.hibernate.version>5.3.2.Final</maven.hibernate.version>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>${maven.compiler.version}</version>
    <goals>
        <goal>compile</goal>
    </goals>
    <configuration>
        <outputDirectory>${project.build.directory}/generated-sources/annotations</outputDirectory>
        <annotationProcessorPaths>
            <annotationProcessorPath>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-jpamodelgen</artifactId>
                <version>${maven.hibernate.version}</version>
            </annotationProcessorPath>
            <annotationProcessorPath>
                <groupId>javax.xml.bind</groupId>
                <artifactId>jaxb-api</artifactId>
                <version>${jaxb.version}</version>
            </annotationProcessorPath>
        </annotationProcessorPaths>
        <annotationProcessors>
            <annotationProcessor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</annotationProcessor>
        </annotationProcessors>
        <compilerArgs>
            <arg>-AaddGeneratedAnnotation=false</arg>
        </compilerArgs>
        <compilerArguments>
            <AaddGeneratedAnnotation>false</AaddGeneratedAnnotation>
            <Adebug>true</Adebug>
        </compilerArguments>
        <failOnError>true</failOnError>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-jpamodelgen</artifactId>
            <version>${maven.hibernate.version}</version>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>${jaxb.version}</version>
            <type>jar</type>
        </dependency>
    </dependencies>
</plugin>
jontejj
  • 2,800
  • 1
  • 25
  • 27
Marc Magon
  • 713
  • 7
  • 11
10

The problem is really in 3.* version of the maven-compiler-plugin. It acts a bit different from the 2.* version. In particular, it seems that maven-compiler-plugin3.* doesn't add its dependencies and build extensions to the classpath because it uses javax.tools instruments for running compile process. To get back the old behavior for maven-compiler-plugin you should use a new configuration property forceJavacCompilerUse:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
    <forceJavacCompilerUse>true</forceJavacCompilerUse>
</configuration>
....
</plugin>
NewUser
  • 3,729
  • 10
  • 57
  • 79
Vadim
  • 1,125
  • 8
  • 18
  • I added that flag and I am still getting the error with Hibernate JPAMetalModelEntityProcessor version 1.3. I have a multi module maven build and the generated classes instead of going into parentmodule/submodule/target/... is going right into parentmodule there is just a com dir dumped there with the classes? Any idea how to fix that? – haskovec Sep 30 '14 at 20:22
4

Please take a look jpa-metamodels-with-maven

For further visitors, I found that there are some significant changes in maven-compiler-plugin 3.x series.

This is how I do this. (I'm the one who you linked)

The point is that my solution does not work with those 3.x series of maven-compiler-plugin.

<project ...>

  <build>

    <extensions>
      <extension>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-jpamodelgen</artifactId>
        <version>1.3.0.Final</version>
      </extension>
    </extensions>

    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.5.1</version> <!-- See this? -->
      </plugin>
    </plugins>

  </build>
</project>
Jin Kwon
  • 20,295
  • 14
  • 115
  • 184
  • 1
    Is there a way to do it with compiler version 3.1? It looks like the new aspectj 1.8.2 is built off of those tools, so they get pulled in anyway and break the build. The generated files seem to be getting dumped in the base dir instead of the target directory. The forceJavacCompilerUse doesn't seem to fix it for me either. – haskovec Sep 30 '14 at 20:44
  • @haskovec I hope the situation is changed. See [jpa-metamodels-with-maven-example](https://github.com/jinahya/jpa-metamodels-with-maven-example). – Jin Kwon Jan 10 '18 at 01:40
  • That was a couple of jobs ago for me. I think I ended up ripping out the meta model generation entirely because it wasn't doing what I needed to do, so I just changed our code to no longer need it. – haskovec Jan 11 '18 at 04:50
2

Not sure what kind of build error you got, but here is my case: I got the following compile error in Idea: Annotation processor 'org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor' not found error

But, when compiled from Maven, it was all fine.

So, the problem of mine was that somehow I got wrong configuration in Idea settings. Particularly, it appeared that Idea somehow detected the processor and put in into the settings of module processor profiles. It is discussed here.

I fixed it as the following:

  1. Go to Idea > Settings > Annotation Processors.
  2. For each processor profile make sure that:
    • Enable annotation processing is Yes;
    • There is no annotation processor FQ name of one you have error about (e.i. "JPAMetaModelEntityProcessor") in the list on the right side. If it is listed there, just select and click '-' minus button to remove it.
Andrew Redko
  • 21
  • 1
  • 3
-1

I think this is a better way to contain such dependencies in profiles to solve such problems.

<profile>
    <id>XXX-profile</id>
    <dependencies>
         <dependency>
             // XXX artifact path
         </dependency>
    </dependencies>
</profile>
Nikita Koval
  • 107
  • 5