META-INF/services in JAR with Gradle
Solution 1
You place META-INF/services/org.example.plugins.PluginService
in src/main/java
, but it's not a source, it's a resource file, therefore it should be placed in resources folder according to Maven directory layout convention, that is
src/main/resources/META-INF/services/org.example.plugins.PluginService
In this case everything should work out of the box.
Solution 2
Meanwhile I found a solution to my problem in a (somewhat) similar Question.
Adding the following to the gradle.build
file, resolves my problem
jar {
from ('./src/main/java') {
include 'META-INF/services/org.example.plugins.PluginService'
}
}
Now the JAR file looks as expected
.
|- org
| `- example
| `- plugins
| `- impl
| `- ExamplePlugin.class
`- META-INF
|- MANIFEST.MF
`- services
`- org.example.plugins.PluginService
Solution 3
Hi Can try this: https://plugins.gradle.org/plugin/com.github.harbby.gradle.serviceloader
Usage
serviceLoader {
serviceInterface 'org.example.plugins.PluginService'
serviceInterface 'org.example.plugins.PluginService2'
}
Solution 4
If you happen to inherit some ant based legacy code that does not follow the maven conventions, the following may help.
Define your source sets to match the legacy structure, and include a line like this:
include 'META-INF/services/**'
In your source sets. This pattern is generic and will pick up all your meta inf services.
Full example below.
sourceSets {
main {
java {
srcDir 'src'
exclude '**/Test*.java'
}
resources {
srcDir 'src'
include '**/*.xml'
include 'META-INF/services/**'
}
}
test {
java {
srcDir 'src'
include '**/Test*.java'
}
resources { srcDir 'resources' }
}
}
pvorb
Updated on August 21, 2020Comments
-
pvorb over 3 years
I wanted to build a plugin module that can be loaded with a
ServiceLoader
. This requires adding a file to theMETA-INF/services
directory, that is named after the service interface and that contains the qualifying path to the class that implements it. Then you can load these services by callingServiceLoader.load()
.Here is an example:
Say we want to provide a plugin interface called
org.example.plugins.PluginService
. We then provide an implementation of this service in the classorg.example.plugins.impl.ExamplePlugin
.If we want to have some sort of plugin mechanism, we could create a JAR file, that contains the implementation. This JAR file must also contain the file
META-INF/services/org.example.plugins.PluginService
. This file must contain one lineorg.example.plugins.impl.ExamplePlugin
to enable the
ServiceLoader
to find the implementation. If that JAR file is in the build path, you can load the plugin by callingIterator<PluginService> it = ServiceLoader.load(PluginService.class).iterator();
That iterator will give you access too all plugins that are found by the
ServiceLoader
.For some reason Gradle doesn't include files into the
META-INF
directory by default. Is there a way to let the resulting JAR contain such a file?I already found the method
metaInf
in classJar
. But I don't know groovy good enough to find the solution on my own. -
pvorb over 11 yearsI won't accept my own answer for now, because I think it's only a workaround. Like @axtavt stated above, it should work without these lines in the
build.gradle
.