13

I try to use maven-shade-plugin for a modular jar:

<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>
        </execution>
    </executions>
    <configuration>
        <minimizeJar>true</minimizeJar>
        <artifactSet>
            <includes>
                <include>javax.xml.bind:jaxb-api</include>
                <include>com.sun.xml.bind:jaxb-impl</include>
            </includes>
        </artifactSet>
        <relocations>
            <relocation>
                <pattern>javax.xml.bind</pattern>
                <shadedPattern>org.update4j.javax.xml.bind</shadedPattern>
            </relocation>
            <relocation>
                <pattern>com.sun.xml.bind</pattern>
                <shadedPattern>org.update4j.com.sun.xml.bind</shadedPattern>
            </relocation>
        </relocations>
    </configuration>
</plugin>

But Maven will remove my module-info.class from the shaded jar, with a warning:

[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.

How can I configure it to leave it?

EDIT: the warning actually happens when it removes the shaded jar's module descriptor, not my own.

Mordechai
  • 15,437
  • 2
  • 41
  • 82
  • 2
    You simply can't cause if you use maven-shade-plugin any kind of modules will be useless cause you are packaging everything into a single jar ..which is the end of module-info... – khmarbaise Aug 08 '18 at 17:38
  • Yeah but the whole bundle is still a module against external modules... – Mordechai Aug 08 '18 at 17:38
  • If it's already a module why are you using maven-shade-plugin? Apart from that cause you are packaging other jar files into it which breaks module-info... – khmarbaise Aug 08 '18 at 18:03
  • I want my module to bundle 2 additional modules but still act as a regular module for the rest of the world. – Mordechai Aug 08 '18 at 18:13
  • 3
    The idea of modules is to strongly capsule modules from each other. If you bundle them you will loose that. You need to see that a shaded jar is not a module and only construct which contradicts the idea of modules..The question is: Why would you like to "bundle two modules" into a single one and what purpose does this "bundled thing" should offer against the two separate modules? – khmarbaise Aug 08 '18 at 19:09
  • @khmarbaise That sounds more of an answer to me actually. Yet makes me think more about the theory of separate module versus "one fat jar". The transitive dependencies and their practices might change drastically for a bigger size of an audience I believe. By any chance, do you have a link for co-relating JPMS transitivity and maven transitivity? – Naman Aug 08 '18 at 19:20
  • 6
    @khmarbaise Shading JARs is a common approach to avoid dependency version conflicts and since the module system does not help with that, shading is still valid in a JPMS world. Using smaller modules during compilation and unit testing provides some benefits (e.g. reliable configuration, no accidental use of dependencies' internals) and deploying a large one does, too (e.g. internals are protected, can be used with jlink), so I think the OP's approach and question are valid. – Nicolai Parlog Aug 09 '18 at 05:47
  • 1
    @Nicolai I do not agree cause if you have version conflicts this can be solved by defining deps in your own pom to overwrite conflicting deps. If you have shaded jar's this option does not work anymore. If you have a module which is capsuled on it's own this can be done also in the pom of the module. If you start to shade this could cause issues only based on the shading cause you are breaking the capsulation. This is caused by having a single module-info ... – khmarbaise Aug 09 '18 at 08:01
  • 3
    (a) With "version conflict" I mean that you _need_ two different versions, say Guava 13 and Guava 20, because of removed/added methods. This is not solvable without class loader trickery or shading. (b) Shading should include [relocating classes into different packages](https://maven.apache.org/plugins/maven-shade-plugin/examples/class-relocation.html). If your dependency shades and relocates Guava 13, you are actually free to use Guava 20 without conflicts. This is not pretty, but sometimes necessary and a common approach to ease dependency hell. Modules do not change its validity. – Nicolai Parlog Aug 09 '18 at 15:37

1 Answers1

8

Because of module-info's in the JPMS world dictate the exposure of a module, shading items in may cause that nasty "Package is read from two different modules" error.

I've solved it the following way

  • Shading in, filtering out module-info across all modules
  • Then adding in the module-info (which may or may not be valid, THANK YOU MODITECT, you have no idea how useful that is)
  <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <configuration>
          <artifactSet>
            <excludes>
              <exclude>module-info.java</exclude>
            </excludes>
          </artifactSet>
        </configuration>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

      <plugin>
        <groupId>org.moditect</groupId>
        <artifactId>moditect-maven-plugin</artifactId>
        <executions>
          <execution>
            <id>add-module-infos</id>
            <phase>package</phase>
            <goals>
              <goal>add-module-info</goal>
            </goals>
            <configuration>
              <overwriteExistingFiles>true</overwriteExistingFiles>
              <module>
                <moduleInfoFile>
                  src/main/java/module-info.java
                </moduleInfoFile>
              </module>
            </configuration>
          </execution>
        </executions>
      </plugin>

This is a really annoying thing, and from everything I've read they have no intention of removing it or adding a flag to bypass it.

Community
  • 1
  • 1
Marc Magon
  • 713
  • 7
  • 11