当运行"mvn dependency:tree"时,Maven无法识别兄弟模块。

110
我正在尝试建立一个多模块Maven项目,但是跨模块依赖似乎没有被正确设置。
我有:
<modules>
  <module>commons</module>
  <module>storage</module>
</modules>

在父POM中(其包装类型为pom),还有子目录commons/storage/,它们定义了具有相同名称的JAR POM。

Storage依赖于Commons。

在主(master)目录中,我运行mvn dependency:tree并看到:

[INFO] Building system
[INFO]    task-segment: [dependency:tree]
[INFO] ------------------------------------------------------------------------
[INFO] [dependency:tree {execution: default-cli}]
[INFO] domain:system:pom:1.0-SNAPSHOT
[INFO] \- junit:junit:jar:3.8.1:test
[INFO] ------------------------------------------------------------------------
[INFO] Building commons
[INFO]    task-segment: [dependency:tree]
[INFO] ------------------------------------------------------------------------
[INFO] [dependency:tree {execution: default-cli}]
...correct tree...
[INFO] ------------------------------------------------------------------------
[INFO] Building storage
[INFO]    task-segment: [dependency:tree]
[INFO] ------------------------------------------------------------------------
Downloading: http://my.repo/artifactory/repo/domain/commons/1.0-SNAPSHOT/commons-1.0-SNAPSHOT.jar
[INFO] Unable to find resource 'domain:commons:jar:1.0-SNAPSHOT' in repository my.repo (http://my.repo/artifactory/repo)
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Failed to resolve artifact.

Missing:
----------
1) domain:commons:jar:1.0-SNAPSHOT
为什么依赖于"commons"失败了,即使反应堆显然已经看到了它,因为它成功处理了它的依赖关系树?它绝对不应该去网络上寻找它,因为它就在那里...
存储的POM:
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <packaging>jar</packaging>
  <parent>
    <artifactId>system</artifactId>
    <groupId>domain</groupId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <groupId>domain</groupId>
  <artifactId>storage</artifactId>
  <name>storage</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <!-- module dependencies -->
    <dependency>
      <groupId>domain</groupId>
      <artifactId>commons</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>

    <!-- other dependencies -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

非常感谢任何建议!

(编辑)

为了澄清,我在这里要表达的是:我不想安装模块X来构建依赖于X的模块Y,而这两个模块都是从同一个父POM引用的模块。对我来说,这是有直觉意义的,如果在同一源树中有两件事,我不应该必须安装中间产品才能继续构建。希望我的思路在这里有些道理……


2
啊,修改得很好。为什么你一开始就没写成这样呢?另外,也许考虑更改标题吧 :) 我不是挑剔,只是为了清晰和分类的缘故。这将有助于整个社区在未来搜索类似问题时(实际标题和内容并不明确,而是关于dependency:tree),更容易找到相关信息。 - Pascal Thivent
1
你好。你找到解决方案了吗?我也有这个问题 :( - user168237
1
编译失败了吗,还是只有依赖树目标失败了?请参考唐·威利斯的答案。 - metamatt
哦,所以如果一个模块因为找不到另一个模块的符号而失败,那么另一个模块应该作为依赖项添加并安装为JAR文件?这是关键... - WesternGun
很遗憾,Maven 3.6 尚未解决这个问题。 - yuxh
9个回答

125

此maven邮件列表线程中所讨论的,dependency:tree目标本身将在存储库中查找内容而不是反应堆。你可以通过mvn安装来解决这个问题,正如先前建议的那样,或者执行一些调用反应堆的不那么繁琐的操作来解决该问题,例如

mvn compile dependency:tree

对我有效。


3
感谢您使用那个便宜的解决方案。但这是一个bug吗?我期望dependency:tree目标不需要任何技巧地依赖于反应器。 - mcoolive
需要注意的是,任何在全局运行的任务都会发生同样的情况,但只会影响某些子项目。 - tkruse
不幸的是,compile 触发了传递依赖项的下载。除了 POM 文件之外,是否还有一种列出依赖树而不实际下载它们的方法? - sschuberth
我在其他目标中也遇到了同样的问题。添加compilevalidate不够用)也有帮助: mvn compile animal-sniffer:checkmvn compile org.basepom.maven:duplicate-finder-maven-plugin:check - msa
根据您的构建方式,某些模块可能还依赖于稍后阶段构建的工件。在我的情况下,使用maven-assembly-plugin构建了一个ZIP文件(在“package”阶段),因此我需要执行例如“mvn package animal-sniffer:check”的操作。 - msa

23

我认为问题在于,当你指定一个依赖时,Maven 期望至少从本地仓库中打包并提供它作为 jar(或其他形式)文件。我相信如果你先在 commons 项目上运行 mvn install,一切都会顺利进行。


4
有没有办法指定我想使用源代码树中的模块版本?我本以为这种情况会自动处理。我不想/不认为 Maven 要求每次我只想制作整个项目时都要进行构建-安装-构建-安装-构建。 - Steven Schlansker
43
你是正确的,运行安装会解决这个问题。但现在每次我做更改时都需要重新安装,这不是我想要的。我希望存储项目能够从公共项目中获取最新的代码。 - Steven Schlansker
6
那是本意想表达的主要问题,我只是在澄清。在原始问题中,我没有清楚地表明我的意图是为了在同一项目中构建其他模块而无需将已构建的产品放入本地仓库,对吗? - Steven Schlansker
对于我来说(插件版本2.10),如果我只执行“dependency:tree”而不是“install dependency:tree”,它并没有什么帮助... - Egon Willighagen
1
多年后为了Google的完整性,正确的答案是按照bsautner的解释,在依赖项中添加pom - earizon
显示剩余3条评论

10
Don Willis的回答中获得的信息,可以关闭answer
如果您的构建创建了测试JAR文件以在反应堆子模块之间共享测试代码,则应使用:
mvn test-compile dependency:tree

在这种情况下,这将允许dependency:tree完成运行。


8
实现这个的方式可能是通过反应堆构建来使依赖关系在不安装的情况下得以解决。如果您在描述项目模块结构的父级中启动构建,则构建本身将通过 Maven 内部反应堆解决模块之间的依赖关系。这当然不是完美的解决方案,因为它不能解决结构内单个模块的构建问题。在这种情况下,Maven 将没有反应堆中的依赖项,并会尝试在存储库中解决它。因此,对于单独的构建,您仍然需要先安装依赖项。这里有一些描述此情况的参考文献:reference

1
有没有办法在不安装依赖项和构建完整父项目的情况下构建单个模块? - Has QUIT--Anony-Mousse
2
为了完整回答这个问题 - 如果插件直接被调用(没有阶段),例如 mvn dependency:tree,它仍然不会解析来自源的依赖项,除非您调用 compile 阶段。因此,这将起作用:mvn compile dependency:tree - Stanislav Bashkyrtsev

5
在像这样的Maven模块结构中:
- parent
  - child1
  - child2

您将在parent pom中看到以下内容:
<modules>
  <module>child1</module>
  <module>child2</module>
</modules>

如果您现在在child2中依赖于child1,可以通过在child2<dependencies>中添加以下内容来实现:
<dependency>
  <groupId>example</groupId>
  <artifactId>child1</artifactId>
</dependency>

你将收到一个错误,提示找不到child1的JAR文件。可以通过在parentpom中声明包括child1<dependencyManagement>块来解决此问题:
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>example</groupId>
      <artifactId>child1</artifactId>
      <version>${project.version}</version>
    </dependency>
  </dependencies>
</dependencyManagement>

在运行parent上的compilepackage等目标时,将会构建child1,并且child2将找到child1的已编译文件。

1
谢谢。这对我真的很有用。不过,为什么Jetty项目在子模块中没有dependencyManagement标签也能正常工作呢?例如,_jetty-io_模块引用了_jetty-util_。 org.eclipse.jetty jetty-util ${project.version} - Kellen

4

对于我来说,引导我来到这个线程的是一个类似的问题,解决方法是确保所有模块依赖的pom文件都有。

 <packaging>pom</packaging>

父级项目使用了pom模型依赖,因此没有找到jar包。


这个错误是这样的:解析POM时出错。原因:未识别的标签:“packaging”。 - hithwen
编辑:我是指<packaging>pom</packaging>,已经修复了。替换<packaging>jar</packaging>。 - bsautner
5
这解决了问题,但现在子模块不会生成可导出的归档文件(即jar、war、ear文件)。 - sheldonh
sheldonh,你有没有找到解决这个错误并生成可导出存档的方法? - user3853134

3
唯一有效的方法:切换到 Gradle。
我有...
Parent
  +---dep1
  +---war1 (using dep1)

我只需进入war1目录并使用mvn tomcat7:run-war命令即可运行项目。尽管war1引用了其父项,父项又引用了war1和dep1(作为模块),所以所有依赖关系应该已知,但我总是必须先安装整个项目。

我不明白问题出在哪里。


2
这就是为什么当我需要创建多模块项目时,我使用Gradle的原因。 :( - Zhuo YING

2
使用版本大于等于3.1.2的依赖插件似乎可以解决这个问题。

0

确保失败的模块在pom中得到解决,通过在模块的pom文件中包含配置来指向正确的父级。


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