Maven 3 - 如何添加注解处理器依赖?

38

我需要在项目源代码上运行一个注解处理器。注解处理器不应成为项目的传递性依赖项,因为它仅用于注解处理而不是其他任何目的。

这是我用于此目的的完整(不起作用的)测试pom:

<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>

我在测试插件的配置中明确将 org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor 定义为注解处理器,但我知道这不是必须的。

我遇到的问题是 hibernate-jpamodelgen 依赖项未添加到编译器类路径中,因此找不到注解处理器,导致构建失败。

根据这个答案,我尝试将该依赖项作为构建扩展添加(不确定我是否理解了它们应该是什么!):

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

这也没有将hibernate-jpamodelgen添加到编译器类路径中。

到目前为止,我发现唯一有效的方法是将依赖项添加到项目的<dependencies>部分。不幸的是,这会在之后将hibernate-jpamodelgen作为传递性依赖项添加,而我想避免这种情况。

我的先前工作设置使用maven-processor-plugin插件来实现我想要的效果。然而,这个插件不受eclipse m2e支持,最新版本的maven-compiler-plugin现在可以正确处理多个编译器参数,所以我宁愿使用后者。

7个回答

45

annotationProcessorPaths选项可在最新版本的Maven编译器插件中使用:

<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>

这样处理器就与实际项目的依赖项分离开来。如果启用了项目的注释处理,Eclipse M2E插件也将选择此选项。


由于某种原因,它并没有起到帮助的作用。一旦我将注解处理器添加为依赖项(编译时),它就按预期工作了。然而,这只是解决问题的旧方法。我是否正确地认为,在<annotationProcessorPaths>中添加构件不需要在依赖项部分也添加该构件?你有什么想法,我错过了什么吗? - sphinks
<annotationProcessorPath>还是<path>文档指出是后者。 - undefined
如果我使用<annotationProcessorPaths>来指定依赖项,我是否仍然需要<annotationProcessors>来指示要使用的实际注解处理器?或者它们会自动被发现吗?或者只有那些带有META-INF/services/javax.annotation.processing.Processor文件的注解处理器依赖项会被自动检测到,而我需要为其他任何注解处理器包括<annotationProcessors>吗? - undefined

28

将该依赖项作为可选依赖项 (<optional>true</optional>)添加。这将会将该依赖项添加到编译过程中,但不会让它成为一个传递性依赖项:

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

如果您在此模块中创建了一个包含所有依赖项的工件(例如 .war 文件),则可以使用 <scope>provided</scope>。这将防止依赖关系成为传递性,并包含在模块生成的工件中。


谢谢,这个可行!不过根据Maven文档中关于作用域的说明,这似乎并不是optionalprovided的预期使用方式。如果没有出现“更好”的答案,我会接受你的答案(嘿,它可行啊!)。 - bernie
此外,看起来 provided 总是会做正确的事情,而 optional 在使用 war 打包时不会。你有没有看到任何 provided 会失败的情况? - bernie
1
不,我想提供的东西会始终为你做正确的事情。我也同意“provided”听起来不太对,但我想你不会找到更好的解决方案了。 - Aleksander Blomskøld
3
“Optional”表示该项不是依赖于其他项目所必需的。如果其他项目需要它,则必须明确声明。通常情况下,其他项目不会需要你的注解处理器,因此这是可选的(非必需的)。要使注解处理器生效,javac需要在编译时的类路径中找到它们,这是Maven中的编译范围(compile scope)。“provided”是一些插件的特殊范围,用于打包/捆绑编译时的依赖项。它们经常被混淆,但如果你考虑其他项目从你的项目中依赖时需要什么,就会更容易理解。 - Christopher
1
在Maven编译器插件的3.5版本中引入了一个新选项"annotationProcessorPaths"。我建议使用它(请参见下面的答案),而不是将处理器JAR作为项目依赖公开。 - Gunnar
1
需要注意的是,“annotationProcessorPaths”可能会无意中覆盖来自父POM的处理器。在子POM中使用<annotationProcessorPaths combine.children="append">可以确保已配置的处理器得到保留。 - Frettman

12

对于JDK 10,我真的不得不有点疯狂才能让它正常工作,希望有人会觉得这很有用。

<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>

10

问题实际上在于 3.* 版本的 maven-compiler-plugin。它与 2.* 版本有一些不同。特别是,似乎 maven-compiler-plugin3.* 版本因为使用 javax.tools 来运行编译进程,所以不会将其依赖项和构建扩展添加到类路径中。要恢复 maven-compiler-plugin 的旧行为,您应该使用一个新的配置属性 forceJavacCompilerUse

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
    <forceJavacCompilerUse>true</forceJavacCompilerUse>
</configuration>
....
</plugin>

我添加了那个标志,但是在使用Hibernate JPAMetalModelEntityProcessor版本1.3时仍然出现错误。我有一个多模块的Maven构建,生成的类没有进入parentmodule/submodule/target/...,而是直接进入parentmodule,只有一个带有类的com目录被倾倒在那里?你有任何修复的想法吗? - haskovec

4

请查看使用Maven生成JPA元模型

对于其他访客,我发现在maven-compiler-plugin 3.x系列中有一些重大变化。

这是我的解决方案。 (我是您链接的人)

关键是我的解决方案无法与maven-compiler-plugin 3.x系列一起使用。

<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>

1
有没有使用编译器版本3.1的方法?看起来新的AspectJ 1.8.2是基于这些工具构建的,所以它们无论如何都会被引入并破坏构建。生成的文件似乎正在将其转储到基本目录而不是目标目录中。forceJavacCompilerUse对我也没有解决它。 - haskovec
@haskovec 我希望情况有所改变。请查看jpa-metamodels-with-maven-example - Jin Kwon
那是我几份工作之前的事了。我想我最终完全删除了元模型生成,因为它没有做我需要做的事情,所以我只是改变了我们的代码,不再需要它。 - haskovec

2
不确定您遇到了什么样的构建错误,但是这是我的情况:
我在Idea中得到了以下编译错误: 找不到注释处理器'org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor' 但是,当从Maven编译时,一切都很好。
所以,我的问题是某种方式在Idea设置中配置错误。特别是,似乎Idea检测到了处理器并将其放入模块处理器配置文件的设置中。在这里讨论过。 我按照以下步骤进行了修复:
  1. 转到Idea&gt;设置&gt;注释处理器。
  2. 对于每个处理器配置文件,请确保:
    • 启用注释处理为Yes;
    • 右侧列表中没有您遇到错误的注释处理器FQ名称(例如“JPAMetaModelEntityProcessor”)。如果列在那里,请选择并单击“-”减号按钮将其删除。

-1

我认为这是一种更好的方式,通过配置文件来包含这些依赖项以解决此类问题。

<profile>
    <id>XXX-profile</id>
    <dependencies>
         <dependency>
             // XXX artifact path
         </dependency>
    </dependencies>
</profile>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接