web-dev-qa-db-fra.com

META-INF/services dans JAR avec Gradle

Je voulais construire un module de plugin qui puisse être chargé avec un ServiceLoader . Cela nécessite l'ajout d'un fichier au répertoire META-INF/services, nommé d'après l'interface de service et contenant le chemin d'accès qualifiant à la classe qui l'implémente. Ensuite, vous pouvez charger ces services en appelant ServiceLoader.load().

Voici un exemple:

Supposons que nous voulions fournir une interface de plug-in appelée org.example.plugins.PluginService. Nous fournissons ensuite une implémentation de ce service dans la classe org.example.plugins.impl.ExamplePlugin.

Si nous voulons avoir une sorte de mécanisme de plugin, nous pourrions créer un fichier JAR contenant l’implémentation. Ce fichier JAR doit également contenir le fichier META-INF/services/org.example.plugins.PluginService. Ce fichier doit contenir une ligne

org.example.plugins.impl.ExamplePlugin

pour permettre à la ServiceLoader de trouver l'implémentation. Si ce fichier JAR se trouve dans le chemin de génération, vous pouvez charger le plug-in en appelant

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

Cet itérateur vous donnera également accès à tous les plugins trouvés par la variable ServiceLoader.

Pour une raison quelconque, Gradle n'inclut pas de fichiers dans le répertoire META-INF par défaut. Existe-t-il un moyen de laisser le fichier JAR résultant contenir un tel fichier?

J'ai déjà trouvé la méthode metaInf in class Jar. Mais je ne sais pas assez bien pour trouver la solution moi-même.

22
pvorb

Vous placez META-INF/services/org.example.plugins.PluginService dans src/main/Java, mais ce n'est pas une source, c'est un fichier de ressources. Par conséquent, il doit être placé dans le dossier des ressources conformément à la convention de mise en forme de répertoire Maven, c'est-à-dire 

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

Dans ce cas, tout devrait fonctionner hors de la boîte.

34
axtavt

En attendant, j'ai trouvé une solution à mon problème dans une (un peu) Question similaire .

Ajouter ce qui suit dans le fichier gradle.build résout mon problème

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

Maintenant, le fichier JAR ressemble comme prévu

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

J'espère qu'ils mettront cela en œuvre dans la tâche du bocal, tout comme le fait ant. Quelqu'un a déjà travaillé dessus: http://fgaliegue.blogspot.fr/2013/06/gradle-serviceloader-support.html

0
gyorgyabraham

Si vous héritez d'un code hérité basé sur ant qui ne respecte pas les conventions Maven, voici ce qui pourrait vous aider.

Définissez vos ensembles source pour qu'ils correspondent à la structure existante et incluez une ligne comme celle-ci:

include 'META-INF/services/**'

Dans vos ensembles de sources. Ce modèle est générique et récupérera tous vos services meta inf.

Exemple complet ci-dessous.

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' }
    }
}
0
Jeremy Bunn

Salut peut essayer ceci: https://plugins.gradle.org/plugin/com.github.harbby.gradle.serviceloader

Usage

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