当库使用 gradle 的 SPI 时,如何正确输出 META-INF?

How do I correctly output META-INF when libraries use SPIs using gradle?

我正在尝试使用 Gradle 和 Java 制作一个测试应用程序,该应用程序使用多个使用 Java 服务提供商接口的库。我认为这意味着我需要修改 META-INF 但我不确定该怎么做。

我得到的错误是 An SPI class of type org.apache.lucene.codecs.codec with nameLucene50does not exist. You need to add the corresponding JAR file supporting this SPI to your classpath. The current classpath supports the following names [ SimpleText]

我认为我需要将 SPI 信息导入 META-INF,但我不确定如何使用 Gradle。

具体来说,我正在尝试在以下构建文件中使用 Lucene 和 Hadoop jar:

apply plugin: 'java'

sourceCompatibility = 1.8
version = '1.0'

repositories {
    mavenCentral()
}

dependencies {
    compile group:'org.apache.lucene', name:'lucene-core', version:'5.0.0'
    compile group:'org.apache.lucene', name:'lucene-queryparser', version:'5.0.0'
    compile group:'org.apache.lucene', name:'lucene-analyzers-common', version:'5.0.0'
    compile group:'org.apache.lucene', name:'lucene-facet', version:'5.0.0'
    compile group:'org.apache.lucene', name:'lucene-codecs', version:'5.0.0'

    compile group:'org.apache.hadoop', name:'hadoop-hdfs', version:'2.6.0'
    compile group:'org.apache.hadoop', name:'hadoop-core', version:'1.2.1'
    compile group:'org.apache.hadoop', name:'hadoop-common', version:'2.6.0'

}

jar
        {

                from {configurations.compile.collect {it.isDirectory() ?it:zipTree(it) }}
                manifest
                        {
                            attributes 'Main-Class': 'LuceneTest'
                        }
        }

lucene-corelucene-codecs 库都提供 org.apache.lucene.codecs.Codec 实现,因此它们都有一个 META-INF/services/org.apache.lucene.codecs.Codec 服务文件。当您合并所有依赖项时,两个文件都会添加到 jar 文件中,但 Lucene 只会看到 lucene-codecs 一个。您可以在 jar 任务中手动合并服务文件,如 this post, which basically finds all the service files and combines them. The easier solution is probably to use something like the Gradle Shadow plugin.

如果您将此添加到 build.gradle,使用 shadowJar 任务而不是 jar 任务应该可以达到您想要的效果。

buildscript {
  repositories { jcenter() }
  dependencies {
    classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.1'
  }
}
apply plugin: 'com.github.johnrengelman.shadow'
shadowJar {
  mergeServiceFiles()
}