Resolving Incompatible Jar Dependency Conflicts with Maven Shade Plugin
The article explains how incompatible JAR versions, such as differing Guava releases required by business code and middleware, can be resolved efficiently by using Maven Shade Plugin to relocate packages, offering a lightweight alternative to heavyweight class‑loader isolation solutions like Pandora or SOFAArk.
The article, authored by the vivo Internet Server Team, addresses the frequent issue of incompatible JAR versions in Java projects, exemplified by a conflict between different versions of Guava required by business code and middleware.
It uses the "wife and mother" metaphor to illustrate the dilemma of choosing which version to keep when both are needed, and describes a typical scenario where Dependency A (business) and Dependency B (middleware) depend on different, conflicting versions of the same library.
Copying the newer library's source code into the project is examined as a possible fix, but the article points out two major drawbacks: extensive transitive dependencies that make the task labor‑intensive, and the maintenance burden of manually updating the copied code when the upstream library changes.
The authors then explore class‑loader isolation approaches. Alibaba’s internal Pandora component and Ant Financial’s open‑source SOFAArk both load different versions of third‑party libraries in separate class loaders, effectively isolating them and eliminating the conflict.
While powerful, such solutions are considered heavyweight for a single project, especially when the organization does not plan to adopt them broadly.
Consequently, the article proposes a lightweight alternative: using the Maven Shade Plugin to relocate (rename) the conflicting packages, allowing both versions to coexist in the same JVM.
The Maven configuration required for this approach is provided below:
<?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.shaded.example</groupId>
<artifactId>guava-wrapper</artifactId>
<version>${guava.wrapper.version}</version>
<name>guava-wrapper</name>
<url>https://example.com/guava-wrapper</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 版本与 guava 版本基本保持一致 -->
<guava.wrapper.version>27.1-jre</guava.wrapper.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.1-jre</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.2</version>
<executions>
<execution>
<id>default-jar</id>
<goals>
<goal>jar</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>default-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>com.google.guava</pattern>
<shadedPattern>com.google.guava.wrapper</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.common</pattern>
<shadedPattern>com.google.common.wrapper</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.thirdparty</pattern>
<shadedPattern>com.google.wrapper.thirdparty</shadedPattern>
</relocation>
</relocations>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"/>
</transformers>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<distributionManagement>
<!-- Maven repository configuration omitted -->
</distributionManagement>
</project>After building and publishing the shaded guava-wrapper artifact, the project can simply depend on it:
<dependency>
<groupId>com.vivo.internet</groupId>
<artifactId>guava-wrapper</artifactId>
<version>27.1-jre</version>
</dependency>The conclusion emphasizes that the Maven Shade Plugin offers a lightweight, low‑cost method to make incompatible JARs coexist, suitable for isolated conflicts. For more pervasive dependency‑conflict pain points, heavyweight class‑loader isolation solutions like Pandora or SOFAArk are recommended.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
vivo Internet Technology
Sharing practical vivo Internet technology insights and salon events, plus the latest industry news and hot conferences.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
