0

I have a multi-module maven project which is making use of the JPMS features. The consumer module is not loading the implementations present in the provider module.

Here's the maven project structure:

ServiceLoaderExample
├── consumer
├── distribution
├── provider
├── service

The interface TestService is defined in the "service" module. The implementation is TestServiceImpl which is defined in the "provider" module. And the main() method in the "consumer" module uses the ServiceLoader API to load up implementations of TestService. And the "distribution" module is where I create a JAR with all of the dependencies using the maven-assesmbly-plugin.

As such, here are the corresponding module-info files:

1 - "service" module (which defines org.example.service.TestService):

module org.example.service {
    exports org.example.service;
}

2 - "provider" module (which defines org.example.provider.TestServiceImpl):

module org.example.provider {
    requires org.example.service;
    provides org.example.service.TestService with org.example.provider.TestServiceImpl;
}

3 - "consumer" module (which uses the ServiceLoader API to get implementations of TestService):

module org.example.consumer {
    requires org.example.service;
    uses org.example.service.TestService;
}

I am using the maven-assesmbly-plugin, and so it's possible things are getting screwed up when the JAR is getting built. For reference, here's the plugin definition:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>3.2.0</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                    <configuration>
                        <archive>
                            <manifest>
                                <mainClass>org.example.consumer.Main</mainClass>
                            </manifest>
                        </archive>
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                    </configuration>
                </execution>
            </executions>
        </plugin>

I'm using Java 13 and Maven 3.6.3, and I'm running the program using the command java -jar distribution-1.0-SNAPSHOT-jar-with-dependencies.jar. What am I doing wrong?

gjvatsalya
  • 1,129
  • 13
  • 29
  • Is `TestServiceImpl` a `public` class with a `public` no-arg constructor? – Andreas Dec 17 '19 at 07:04
  • @Andreas Yes, it is. – gjvatsalya Dec 17 '19 at 07:07
  • 1
    You can't use jar-with-dependencies("Uber-jar") and expect modules and services to work... [Modules are strictly 1 module per jar file and support is "Defer to future release"](http://openjdk.java.net/projects/jigsaw/spec/issues/#MultiModuleExecutableJARs). The "normal" approach for creating a single distributable consisting of many modules is to create a [jlink image](https://docs.oracle.com/javase/9/tools/jlink.htm#JSWOR-GUID-CECAC52B-CFEE-46CB-8166-F17A8E9280E9). – John Stringer Dec 17 '19 at 10:40
  • Not sure if it is relevant to this question, but I found I could make ServiceLoader in module A see implementations in module B if module A depends on module B. Not exactly how I'd define "plug-in," but I am sure I'm missing some maven magic to discover and load modules somehow. (If I read your module definitions right, that isn't what you did either [packing it all in one jar would, however, solve that problem], but as I mentioned, it seems all wrong to have to do that anyway...) – Erk Dec 28 '20 at 05:15

1 Answers1

0

I was unable to get it work with an uber-jar, however, everything does work when using JLink. So decided to just use JLink instead.

gjvatsalya
  • 1,129
  • 13
  • 29