VB_
VB_

Reputation: 45732

How to resolve split package issue in Java 9

Issue

I have module-info.java file that looks like:

module server {
 
   ...
   // split package issue: lot of java classes within packages with the same name
   requires hbase.common;
   requires hbase.client;
   ...
}

Workaround 1

Problem can't be solved by maven-shader-plugin, because it doesn't know groupId, only package name. Means shader will rename the same packages from both: hbase.common and hbase.client - split package problem remains.

Workaround 2

I also tried to create some shader middlelayer module, to throw away unneeded packages and resolve split package issue. But this solution also does not work.

shader/module-info.java:

module shader {
    requires hbase.common;
    // exports only packages I do need at my code. Shade unneded packages
    // IS THERE ANY WAY TO MAKE IT WORK?
    // Got: X module reads package org.apache.hadoop.hbase.util from both shader and hbase.common
    exports org.apache.hadoop.hbase.util;
} 

server/module-info.java

module server {
    requires shader;
    requires hbase.client;
}

PS

Are there any Maven plugins for combining split-package jars?

Upvotes: 3

Views: 3232

Answers (1)

VB_
VB_

Reputation: 45732

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

Upvotes: 2

Related Questions