【问题标题】:Maven Shade Plugin causes duplicate jars on classpath when running integration tests运行集成测试时,Maven Shade Plugin 会导致类路径上出现重复的 jar
【发布时间】:2019-06-13 19:53:47
【问题描述】:

我有一个项目,其中包含来自AWS's Java v2 SDK 的 S3 依赖项并构建了一个带阴影的 jar。从终端运行我的集成测试时,我点击了this problem。问题是拦截器被添加了两次,因为类路径包含两个带有 S3 jar 的 jar:一次在我的阴影 jar 中,一次来自本地 .m2 存储库。不幸的是,我无法控制包含此问题的代码,因此我需要找到解决方法,直到问题得到解决。

我已经用以下 pom 和测试类复制了这个问题:

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.stu</groupId>
    <artifactId>duplicate-jars-classpath</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <aws.sdk.version>2.5.62</aws.sdk.version>
        <junit.version>5.4.2</junit.version>
        <maven.failsafe.plugin.version>2.22.0</maven.failsafe.plugin.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>software.amazon.awssdk</groupId>
                <artifactId>bom</artifactId>
                <version>${aws.sdk.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter-api</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter-engine</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>s3</artifactId>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <createDependencyReducedPom>false</createDependencyReducedPom>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>${maven.failsafe.plugin.version}</version>
                <configuration>
                    <includes>
                        <include>**/*Test.java</include>
                    </includes>
                </configuration>
                <executions>
                    <execution>
                        <id>run-tests</id>
                        <phase>integration-test</phase>
                        <goals>
                            <goal>integration-test</goal>
                            <goal>verify</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>


</project>

测试类 - src/test/java/com/stu/S3DuplicateJarTest.java

package com.stu;

import java.util.Collections;

import org.junit.jupiter.api.Test;

import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory;

public class S3DuplicateJarTest {

    @Test
    void check_for_duplicate_jars() throws Exception {
        System.out.println("********** AWS execution interceptors:");
        Collections.list(
                new ClasspathInterceptorChainFactory().getClass().getClassLoader()
                        .getResources("software/amazon/awssdk/services/s3/execution.interceptors")
        ).forEach(System.out::println);
    }
}

如果我在 IDE 中运行测试,则输出如下:

********** AWS execution interceptors:
jar:file:/Users/<name>/.m2/repository/software/amazon/awssdk/s3/2.5.48/s3-2.5.48.jar!/software/amazon/awssdk/services/s3/execution.interceptors

从终端这是运行mvn clean verify时的输出:

[INFO] Running com.stu.S3DuplicateJarTest
********** AWS execution interceptors:
jar:file:/Users/<name>/Development/duplicate-jars-classpath/target/duplicate-jars-classpath-1.0-SNAPSHOT.jar!/software/amazon/awssdk/services/s3/execution.interceptors
jar:file:/Users/<name>/.m2/repository/software/amazon/awssdk/s3/2.5.62/s3-2.5.62.jar!/software/amazon/awssdk/services/s3/execution.interceptors

如你所见,终端找到了两个匹配路径的资源。

有什么办法可以避免这种情况吗?我的配置有问题吗?

【问题讨论】:

    标签: java amazon-web-services maven maven-shade-plugin maven-failsafe-plugin


    【解决方案1】:

    这是由于您的 maven 配置,shade 插件将所有依赖项打包到一个 jar 文件中。

    您的 failsafe 插件使用来自项目依赖项 (.m2/...) 和单个 jar 文件的类路径运行测试,因此会产生重复的资源。

    这似乎只有在命令行中使用failsafe 时才会发生。而且它很容易绕过,您可以简单地告诉failsafe 不要加载该依赖项。 (无论如何它都可以在单个 jar 文件中使用)

      <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-failsafe-plugin</artifactId>
          <version>${maven.failsafe.plugin.version}</version>
          <configuration>
              <includes>
                  <include>**/*Test.java</include>
              </includes>
              <classpathDependencyExcludes>
                  <classpathDependencyExcludes>software.amazon.awssdk:s3</classpathDependencyExcludes>
              </classpathDependencyExcludes>
          </configuration>
          <executions>
              <execution>
                  <id>run-tests</id>
                  <phase>integration-test</phase>
                  <goals>
                      <goal>integration-test</goal>
                      <goal>verify</goal>
                  </goals>
              </execution>
          </executions>
      </plugin>
    

    【讨论】:

    • 谢谢!我更进一步,添加了runtime 的范围排除以排除所有编译和运行时依赖项。因为我有一个带有所有依赖项的阴影 jar,所以这是完全可以接受的。这是&lt;classpathDependencyScopeExclude&gt;runtime&lt;/classpathDependencyScopeExclude&gt; 的配置maven.apache.org/surefire/maven-failsafe-plugin/examples/…
    • 请注意,如果您使用此配置,IntelliJ 还会排除运行时范围的依赖项。但是,IntelliJ 不会在阴影 JAR 上运行测试,所以现在您错过了所有运行时依赖项,并且 IntelliJ 将失败并出现 NoClassDefFoundError。
    猜你喜欢
    • 2013-11-28
    • 1970-01-01
    • 2012-05-05
    • 2019-05-08
    • 2011-04-07
    • 2020-01-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多