META-INF / servicios en JAR con Gradle

Quería construir un módulo de complemento que se pueda cargar con un ServiceLoader . Esto requiere agregar un archivo al directorio META-INF/services , que lleva el nombre de la interfaz del servicio y que contiene la ruta calificada a la clase que lo implementa. Luego puede cargar estos servicios llamando a ServiceLoader.load() .

Aquí hay un ejemplo:

Digamos que queremos proporcionar una interfaz de plugin llamada org.example.plugins.PluginService . Luego proporcionamos una implementación de este servicio en la clase org.example.plugins.impl.ExamplePlugin .

Si queremos tener algún tipo de mecanismo de complemento, podríamos crear un archivo JAR, que contenga la implementación. Este archivo JAR también debe contener el archivo META-INF/services/org.example.plugins.PluginService . Este archivo debe contener una línea.

 org.example.plugins.impl.ExamplePlugin 

para habilitar el ServiceLoader para encontrar la implementación. Si ese archivo JAR está en la ruta de comstackción, puede cargar el complemento llamando

 Iterator it = ServiceLoader.load(PluginService.class).iterator(); 

Ese iterador le dará acceso también a todos los complementos encontrados por ServiceLoader .

Por alguna razón, Gradle no incluye archivos en el directorio META-INF de forma predeterminada. ¿Hay alguna manera de permitir que el archivo JAR resultante contenga dicho archivo?

Ya encontré el método metaInf en la clase Jar . Pero no sé lo suficientemente bueno como para encontrar la solución por mi cuenta.

META-INF/services/org.example.plugins.PluginService en src/main/java , pero no es una fuente, es un archivo de recursos, por lo tanto, debe colocarse en la carpeta de recursos según la convención de diseño de directorios de Maven, es decir

 src/main/resources/META-INF/services/org.example.plugins.PluginService 

En este caso todo debería funcionar fuera de la caja.

Mientras tanto, encontré una solución a mi problema en una pregunta (algo) similar .

Agregando lo siguiente al archivo gradle.build , resuelve mi problema

 jar { from ('./src/main/java') { include 'META-INF/services/org.example.plugins.PluginService' } } 

Ahora el archivo JAR se ve como se esperaba

 . |- org | `- example | `- plugins | `- impl | `- ExamplePlugin.class `- META-INF |- MANIFEST.MF `- services `- org.example.plugins.PluginService 

Esperemos que implementen esto en la tarea jar como lo hace ant. Alguien ya trabajó en él: http://fgaliegue.blogspot.fr/2013/06/gradle-serviceloader-support.html

Si le sucede que hereda un código heredado basado en ants que no sigue las convenciones de Maven, lo siguiente puede ayudar.

Defina sus conjuntos de fonts para que coincidan con la estructura heredada e incluya una línea como esta:

include 'META-INF/services/**'

En sus conjuntos de fonts. Este patrón es genérico y recogerá todos sus servicios de meta inf.

Ejemplo completo a continuación.

 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' } } } 

Hola, puedes intentar esto: https://plugins.gradle.org/plugin/com.github.harbby.gradle.serviceloader

Uso

 serviceLoader { serviceInterface 'org.example.plugins.PluginService' serviceInterface 'org.example.plugins.PluginService2' }