Плагин Quarkus Gradle: переопределение дублирующихся записей файлов, поступающих из библиотек зависимостей - PullRequest
1 голос
/ 30 апреля 2020

Могу ли я сообщить плагину Quarkus Gradle (gradle quarkusDev или gradlew quarkusBuild -Dquarkus.package.uber-jar=true), чтобы использовать ресурсы, предоставленные мной, вместо выбора ресурсов из банок зависимостей, когда они дублируются?

Я получаю эти сообщения при сборке uber-jar:

Duplicate entry META-INF/org.apache.uima.fit/types.txt entry from de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.api.segmentation-asl::jar:1.10.0(runtime) will be ignored. Existing file was provided by de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.api.syntax-asl::jar:1.10.0(runtime)
Duplicate entry META-INF/org.apache.uima.fit/types.txt entry from de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.api.lexmorph-asl::jar:1.10.0(runtime) will be ignored. Existing file was provided by de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.api.syntax-asl::jar:1.10.0(runtime)
Duplicate entry META-INF/org.apache.uima.fit/types.txt entry from de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.api.metadata-asl::jar:1.10.0(runtime) will be ignored. Existing file was provided by de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.api.syntax-asl::jar:1.10.0(runtime)
Duplicate entry META-INF/org.apache.uima.fit/types.txt entry from de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.api.ner-asl::jar:1.10.0(runtime) will be ignored. Existing file was provided by de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.api.syntax-asl::jar:1.10.0(runtime)

Эти библиотеки DKPro / uimaFIT являются библиотеками NLP, которые содержат все свои собственные файлы META-INF/org.apache.uima.fit/types.txt. Предполагается, что вы должны объединить эти файлы самостоятельно и добавить свои собственные типы, а затем только включить этот вновь объединенный файл в свой uber-jar или как первый в своем пути к классам.

В параметре quarkus.package.user-configured-ignored-entries есть application.properties, но он также удаляет мои собственные предоставленные файлы. Так что это не то, что я хочу (см. Также https://github.com/quarkusio/quarkus/blob/master/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarResultBuildStep.java#L186). Я не проверял источники gradle quarkusDev, но он приводит к тем же исключениям времени выполнения.

Для справки для других людей, использующих uimaFIT, этот неправильный файл META-INF/org.apache.uima.fit/types.txt приводит к ошибке, подобной org.apache.uima.analysis_engine.AnalysisEngineProcessException: JCas type "org.apache.uima.conceptMapper.support.tokenizer.TokenAnnotation" used in Java code, but was not declared in the XML type descriptor..

Итак, мой вопрос, как мне сказать Gradle или Quarkus использовать этот файл, предоставленный мной, вместо случайного выбора файла из jar зависимости?

Пример сценария Gradle, написанный на Kotlin DSL. Задача generateNlpFiles и функция joinResources автоматически генерируют Java исходные файлы из XML файлов в src/main/typesystem в build/generated/sources/jcasgen/main/, как того требует uimaFIT, и объединяют дублирующиеся ресурсы, такие как META-INF/org.apache.uima.fit/types.txt, в /generated/resources/uimafit/ , Вам не нужно смотреть на них слишком усердно.

import java.io.FileOutputStream
import java.net.URLClassLoader
import org.apache.commons.io.IOUtils

plugins {
    id("java")
    id("io.quarkus")
    id("eclipse")
}

repositories {
    jcenter()
    // required for downloading OpenNLP models
    maven("https://zoidberg.ukp.informatik.tu-darmstadt.de/artifactory/public-releases/")
}

group = "com.example"
version = "0.0.0-SNAPSHOT"

java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11

dependencies {
    val quarkusPlatformGroupId: String by project
    val quarkusPlatformArtifactId: String by project
    val quarkusPlatformVersion: String by project
    // Quarkus dependencies
    implementation(enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}"))
    implementation("io.quarkus:quarkus-jaxb")
    implementation("io.quarkus:quarkus-jackson")
    implementation("io.quarkus:quarkus-resteasy")
    implementation("io.quarkus:quarkus-jdbc-mariadb")
    implementation("io.quarkus:quarkus-resteasy-jsonb")
    implementation("io.quarkus:quarkus-smallrye-openapi")
    implementation("io.quarkus:quarkus-container-image-docker")
    // UIMA
    implementation("org.apache.uima:uimaj-core:2.10.3")
    implementation("org.apache.uima:ConceptMapper:2.10.2")
    implementation("org.apache.uima:uimafit-core:2.4.0")
    // DKPro
    implementation("de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.io.xmi-asl:1.10.0")
    implementation("de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.api.metadata-asl:1.10.0")
    implementation("de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.langdetect-asl:1.10.0")
    implementation("de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.icu-asl:1.10.0")
    implementation("de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.opennlp-asl:1.10.0")
    implementation("de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.opennlp-model-tagger-de-maxent:20120616.1")
    implementation("de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.opennlp-model-tagger-en-maxent:20120616.1")
    implementation("de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.opennlp-asl:1.10.0")
    implementation("de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.opennlp-model-ner-de-nemgp:20141024.1")
    implementation("de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.opennlp-model-ner-en-location:20100907.0")
    implementation("de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.opennlp-model-ner-en-organization:20100907.0")
    implementation("de.tudarmstadt.ukp.dkpro.core:de.tudarmstadt.ukp.dkpro.core.opennlp-model-ner-en-person:20130624.1")
    // tests
    testImplementation("io.quarkus:quarkus-junit5")
    testImplementation("io.rest-assured:rest-assured")
    // for generating NLP type system during compile time
    compileOnly("org.apache.uima:uimaj-tools:2.10.4")
}

// joins resource files from classpath into single file
fun joinResources(classLoader: URLClassLoader, inputResourceName: String, outputFile: File) {
    val outputStream = FileOutputStream(outputFile)
    val resources = classLoader.findResources(inputResourceName).toList()
    resources.forEach {
        val inputStream = it.openStream()
        IOUtils.copy(inputStream, outputStream)
        outputStream.write('\n'.toInt());
        inputStream.close()
    }
    outputStream.close()
}

// generate NLP type system from XML files and join uimaFIT files
val generateNlpFiles = task("generateNlpFiles") {
    inputs.files(fileTree("src/main/typesystem"))
    inputs.files(fileTree("src/main/resources"))
    outputs.dir("${buildDir}/generated/sources/jcasgen/main/")
    outputs.dir("${buildDir}/generated/resources/uimafit/")

    val compileClasspath = project.sourceSets.main.get().compileClasspath
    val runtimeClasspath = project.sourceSets.main.get().runtimeClasspath
    val compileClassLoader = URLClassLoader(compileClasspath.map{ it.toURI().toURL() }.toTypedArray())
    val runtimeClassLoader = URLClassLoader(runtimeClasspath.map{ it.toURI().toURL() }.toTypedArray())

    // from XML files in src/main/typesystem/ generate Java sources into build/generated/sources/jcasgen/main/
    val jCasGen = compileClassLoader.loadClass("org.apache.uima.tools.jcasgen.Jg").newInstance()
    fileTree("src/main/typesystem").forEach() { typeSystemFile ->
        doFirst {
            // see https://github.com/Dictanova/gradle-jcasgen-plugin/blob/master/src/main/groovy/com/dictanova/jcasgen/gradle/JCasGenTask.groovy#L45
            val jcasgeninput = "${typeSystemFile}"
            val jcasgenoutput = "${buildDir}/generated/sources/jcasgen/main/"
            val jcasgenclasspath = "${runtimeClasspath.asPath}"
            val arguments: Array<String> = arrayOf("-jcasgeninput", jcasgeninput, "-jcasgenoutput", jcasgenoutput, "-jcasgenclasspath", jcasgenclasspath)
            val main1 = jCasGen.javaClass.getMethod("main1", arguments.javaClass)
            main1.invoke(jCasGen, arguments)
        }
    }

    // collect types.txt and components.txt from classpath and join them in build/generated/resources/uimafit/META-INF/org.apache.uima.fit/
    val uimafitDir = "${buildDir}/generated/resources/uimafit/META-INF/org.apache.uima.fit"
    mkdir(uimafitDir)
    joinResources(runtimeClassLoader, "META-INF/org.apache.uima.fit/types.txt", File("${uimafitDir}/types.txt"))
    joinResources(runtimeClassLoader, "META-INF/org.apache.uima.fit/components.txt", File("${uimafitDir}/components.txt"))
}

eclipse {
    project {
        natures(
                "org.eclipse.wst.common.project.facet.core.nature",
                "org.eclipse.buildship.core.gradleprojectnature"
        )
    }
    classpath {
        file.withXml {
            val attributes = mapOf("kind" to "src", "path" to "build/generated/sources/jcasgen/main")
            this.asNode().appendNode("classpathentry", attributes)
        }
    }
}

tasks {
    compileJava {
        options.encoding = "UTF-8"
        options.compilerArgs.add("-parameters") // was in original Quarkus Gradle file, not sure what this does
        dependsOn(generateNlpFiles)
        // add generated sources to source sets
        sourceSets["main"].java.srcDir(file("${buildDir}/generated/sources/jcasgen/main/"))
        sourceSets["main"].resources.srcDir(file("${buildDir}/generated/resources/uimafit/"))
    }
    compileTestJava {
        options.encoding = "UTF-8"
    }
    "eclipse" {
        dependsOn(generateNlpFiles)
    }
}

Один из обходных путей - использовать gradlew quarkusBuild -Dquarkus.package.uber-jar=true с записями в quarkus.package.user-configured-ignored-entries и добавлять свои собственные файлы вручную в получившийся jar, но это не будет работать с gradle quarkusDev.

Я использую Quarkus 1.3.2, поскольку Quarkus 1.4.1 не может обрабатывать несколько каталогов ресурсов (см. также https://github.com/quarkusio/quarkus/blob/master/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusDev.java#L391), как того требует мой проект .

Я также пытался исключить файлы с некоторыми плагинами Gradle JarJar, такими как https://github.com/shevek/jarjar, но не смог их запустить.

1 Ответ

1 голос
/ 30 апреля 2020

Прямо сейчас, вы не можете, просто возьмите один из банок, предоставляющих его.

Не могли бы вы создать запрос функции в нашем трекере: https://github.com/quarkusio/quarkus/issues/new?assignees=&labels=kind%2Fenhancement&template=feature_request.md&title=.

Звучит как что-то полезное.

Спасибо!

...