Search code examples
javamavenclassloadervert.xserviceloader

How to register a SPI implementation when running exec:java


I'm trying to make VertX Mertrics work when running via the exec:java Maven plugin.

All works as expected when I package the application into a fatjar and run it with java -jar fat.jar -conf config.json -Dvertx.metrics.options.enabled=true

When I run it with mvn clean package exec:java -DskipTests I see: 2016-03-22 18:39:58.833 WARN i.v.c.i.VertxImpl:348 - Metrics has been set to enabled but no VertxMetricsFactory found on classpath

I tried several approaches:

  • adding io.vertx:vertx-dropwizard-metrics:3.2.1 as compile dependency
  • create an in-house metrics implementation and register it by means of src/main/resources/META-INF/services/io.vertx.core.spi.VertxMetricsFactory file (double-checked that it's actually copied to target/classes/META-INF/services/io.vertx.core.spi.VertxMetricsFactory)
  • also adding ${basedir}/src/main/resources as additional classpath element (in addition to previous point)

I have double-checked in the debugger that ServiceLoader actually returns an empty iterator.

This is my exec-plugin config: <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <configuration> <additionalClasspathElements> <element>${basedir}/src/main/resources</element> </additionalClasspathElements> <mainClass>io.vertx.core.Launcher</mainClass> <commandlineArgs>run ${vertx.mainVerticle} -conf ${vertx.config}</commandlineArgs> <systemProperties> <systemProperty> <key>vertx.logger-delegate-factory-class-name</key> <value>io.vertx.core.logging.SLF4JLogDelegateFactory</value> </systemProperty> <systemProperty> <key>vertx.metrics.options.enabled</key> <value>true</value> </systemProperty> </systemProperties> </configuration> </plugin>

Here is exec:exec configuration that does work, but I want to understand if and why it's (im-)possible to do it with exec:java

<profile> <id>exec</id> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <executions> <execution> <goals> <goal>exec</goal> </goals> <phase>process-classes</phase> <configuration> <executable>java</executable> <arguments> <argument>-Dvertx.metrics.options.enabled=true</argument> <argument>-Dvertx.logger-delegate-factory-class-name=${vertx.logger-delegate-factory-class-name}</argument> <argument>-classpath</argument> <classpath /> <argument>io.vertx.core.Launcher</argument> <argument>run</argument> <argument>${vertx.mainVerticle}</argument> <argument>-conf</argument> <argument>${vertx.config}</argument> </arguments> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile>


Solution

  • Did you try exec:exec instead of exec:java?

    exec:exec runs in a separate process, and this might solve your problem.

    ServiceLoader uses the application class loader to load any classes listed in META-INF/services. This is why ServiceLoader often does not work in environments with custom class loaders (e.g. OSGi).

    Since Maven constructs its own class loader for each Maven plugin, even if you declare compile time dependencies containing your SPI, these classes will only be visible to the Maven class loader, but not to the application class loader.