Important this approach does not work when the same package exposes different classes from different modules and both of them are required. It only works if different packages are used, so you can filter-out packages from conflicting JARs.
So, the problem - two dependencies (maybe transitive) with the same package name. It's not compatible with JMPS and failfast during compilation. The solution of this problem is to manually (with maven-shade-plugin)exclude conflicting packages from one of the dependencies.
maven-shade-plugin has per-class or per-package include/exclude functionality. Here is documentation.
Not working solution (explanation of the problem)
The problem was that this approach doesn't work at first glance. If you will put the plugin at the same pom.xml
where you imported both conflicting JARs - compilation will fail due "module X reads package org.apache.hadoop.hbase.util from both hbase.client and hbase.common "
. JPMS is run at compilation phase (before package phase where plugin is launched). Here is an example:
server/
|-src/
| |-main/
| |-java/
| |-com.somapackage
| |-module-info.java
| [
| module server {
| requires java.base;
| requires hbase.common; //they have lots of conflicting packages
| requires hbase.client; //they have lots of conflicting packages
| }
| ]
|-pom.xml
[
<dependencies>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-common</artifactId>
<version>${hbase.common.version}</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>${hbase.client.version}</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>false</minimizeJar>
<filters>
<filter>
<artifact>org.apache.hbase:hbase-client</artifact>
<excludes>
<exclude>org/apache/hadoop/hbase/util/ **</exclude>
</excludes>
</filter>
<filter>
<artifact>org.apache.hbase:hbase-common</artifact>
<includes>
<include>org/apache/hadoop/hbase/util/ **</include>
</includes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
]
Working solution
To make JPMS split package validation work after shading we have to move conflicting dependencies to separate submodule. Moreover, we have to manually resolve packages conflict (exclude the same package from one dependency and include into another dependency) - that means we have to create to different sumbodules: shader1
and shader2
. Here is the code:
server/
|-src/
| |-main/
| |-java/
| |-com.somapackage
| |-module-info.java
| [
| module server {
| requires java.base;
| requires shader1;
| requires shader2;
| }
| ]
|-pom.xml
[
<dependency>
<groupId>com.organization.proj</groupId>
<artifactId>shader1</artifactId>
<version>${proj.version}</version>
<scope>system</scope>
<systemPath>${project.basedir}/../shader/target/shader1-0.0.1.jar</systemPath>
</dependency>
<dependency>
<groupId>com.organization.proj</groupId>
<artifactId>shader2</artifactId>
<version>${proj.version}</version>
<scope>system</scope>
<systemPath>${project.basedir}/../shader2/target/shader2-0.0.1.jar</systemPath>
</dependency>
]
|
|
shader1
|-src/
| |-main/
| |-java/
| |-com.somapackage
| |-module-info.java
| [
| module shader1 {
| requires java.base;
| requires transitive hbase.client;
| }
| ]
|-pom.xml
[
<dependencies>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>${hbase.client.version}</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>false</minimizeJar>
<filters>
<filter>
<artifact>org.apache.hbase:hbase-client</artifact>
<excludes>
<exclude>org/apache/hadoop/hbase/util/ **</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
]
|
|
shader2
|-src/
| |-main/
| |-java/
| |-com.somapackage
| |-module-info.java
| [
| module shader2 {
| requires java.base;
| requires transitive hbase.common;
| }
| ]
|-pom.xml
[
<dependencies>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-common</artifactId>
<version>${hbase.common.version}</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>false</minimizeJar>
<filters>
<filter>
<artifact>org.apache.hbase:hbase-common</artifact>
<includes>
<include>org/apache/hadoop/hbase/util/ **</include>
</includes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
]
- do not forget to use
require transitive
at shader submodules