运行 集成测试时,Maven Shade 插件会导致类路径上出现重复的 jar

Maven Shade Plugin causes duplicate jars on classpath when running integration tests

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

我已经用下面的 pom 和测试复制了这个问题 class:

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>

测试class - 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

这是 运行ning 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

如您所见,终端已找到两个与路径匹配的资源。

我能做些什么来避免这种情况吗?我的配置有问题吗?

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

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

不过,这似乎只有在命令行中使用 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>