Feri
Feri

Reputation: 1111

JDK9 Automatic Modules and "Split Packages" Dependencies

I am converting a java project to use modules. One of my modules depends on hamcrest library, and it needs both of the jar files hamcrest.core and hamcrest.library. These two jar files both have org.hamcrest package. So when my module wants to treat these two jars as automatic modules, it fails because two modules in a module-path cannot have packages with same name. I searched a lot and found some related stuff on stackoverflow. It seems that I have two reasonable options if I do not want to rebuild those dependencies:

  1. Merge the two jars into one jar using my build automation tool (which is maven).
  2. Somehow tell java compiler that these two jars should be treated as a single automatic module.

So here are my questions:

Thanks in advance

Upvotes: 4

Views: 1193

Answers (2)

Tiddo
Tiddo

Reputation: 6544

I have a slight variation on Feri' solution.

For me, I ran into 3 problems with the maven-assembly-plugin in a multi-module maven project.

First, the generated jar contains not only the requested dependencies, but also transitive dependencies.

Secondly, for reasons I don't quite understand, the maven-assembly-plugin puts a generated module-info.class into my jars, which breaks the solution entirely.

Thirdly, IntelliJ doesn't seem to understand this setup, and complains about missing modules.

The first 2 problems can be solved by switching from the maven-assembly-plugin to the maven-shade-plugin, like so:

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.6.0</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <artifactSet>
                                <includes>
                                    <include>[group-id:artifact-id]</include>
                                    <include>[...]</include>
                                </includes>
                            </artifactSet>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

This generates a jar with only the specified modules, and without a module-info.class.

After switching to the maven-shade-plugin, we can now also solve the 3rd problem: first, we create a module-info.java in our hamcrest.all that requires transitively all dependencies. This makes IntelliJ understand what modules are being exposed from the module:

module hamcrest.all {
  requires transitively hamcrest-core;
  requires transitively hamcrest-library;
}

But clearly, this won't actually compile due to the split-module problem. We have one final trick: since hamcrest.all doesn't have any source code itself, we can just disable source code compilation for the module:

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <executions>
                    <execution>
                        <id>default-compile</id>
                        <phase>none</phase>
                    </execution>
                </executions>
            </plugin>

Upvotes: 0

Feri
Feri

Reputation: 1111

Ok I finally managed to solve it like this:

  1. Create a new maven module called hamcrest-all and add dependencies on hamcrest-core and hamcrest-library.
  2. add maven-assembly-plugin to this module with appendAssemblyId set to false.
  3. remove the dependency to hamcrest-core and hamcrest-library from other maven modules and instead add dependency to hamcrest-all.
  4. exclude hamcrest-core and hamcrest-library when including dependency to hamcrest-all.

What it actually does is that it unpacks hamcrest-core and hamcrest-library in the jar file created for hamrest-all. And because each jar file is treated as one module by JMPS, the problem is gone :)

Upvotes: 6

Related Questions