Как добавить клиент OpenAPI в качестве подпроекта?

Я могу успешно добавить сгенерированный клиент openapi в свой проект через наборы исходных текстов. Но затем мне нужно скопировать зависимости в главный build-gradle, разрешить конфликты - ›Я думаю, что было бы лучше, если бы клиент был подпроектом со своим собственным build.gradle.

Поэтому я добавляю include = 'build:openapi-java-client' к моим settings.gradle и compile project(':build:openapi-java-client') к своим зависимостям. Итак, у меня есть следующие файлы:
build.gradle:

plugins {
    id 'java'
    id 'application'
    id "org.openapi.generator" version "4.3.1"
}

repositories {
    jcenter()
}

openApiGenerate {
    generatorName = "java"
    inputSpec = "$rootDir/specs/petstore.yaml".toString()
    outputDir = "$buildDir/openapi-java-client".toString()
    apiPackage = "org.openapi.example.api"
    invokerPackage = "org.openapi.example.invoker"
    modelPackage = "org.openapi.example.model"
    configOptions = [
        dateLibrary: "java8"
    ]
}

dependencies {
    implementation 'com.google.guava:guava:29.0-jre'
    testImplementation 'junit:junit:4.13'
    
    compile project(':build:openapi-java-client')
}

application {
    mainClassName = 'a.aa.App'
}

и settings.gradle:

rootProject.name = 'simple-java-app'
include = 'build:openapi-java-client'

Я выполняю openApiGenerate заранее, после добавления в качестве подпроекта делаю Gradle - ›Обновить проект Gradle и Обновить.

Затем Eclipse показывает мне проблему:

Could not run phased build action using Gradle distribution 'https://services.gradle.org/distributions/gradle-6.5.1-bin.zip'.
Settings file 'C:\...\simple-java-app\settings.gradle' line: 11
A problem occurred evaluating settings 'simple-java-app'.
Could not set unknown property 'include' for settings 'simple-java-app' of type org.gradle.initialization.DefaultSettings.

Я не знаю, куда идти дальше, адресация подпроектов в подпапках работала отлично, когда я работал с https://guides.gradle.org/creating-multi-project-builds/ и поместите greeting-library в подпапку.


person peer    schedule 26.07.2020    source источник


Ответы (3)


Вы пытаетесь сделать build/ проект, когда этот каталог специально не предназначен для использования в качестве каталога проекта. Это каталог build по умолчанию Gradle и, вероятно, 99% других подключаемых модулей и других подключаемых модулей Gradle.

Просто измените каталог output на что-нибудь другое, кроме build/:

openApiGenerate {
    generatorName.set("java")
    inputSpec.set("$rootDir/specs/petstore.json")
    outputDir.set("$rootDir/openapi-java-client")
    apiPackage.set("org.openapi.example.api")
    invokerPackage.set("org.openapi.example.invoker")
    modelPackage.set("org.openapi.example.model")
}

Затем включите проект в свою сборку с правильным синтаксисом:

// settings.gradle
include("openapi-java-client")

Однако использование org.openapi.generator, похоже, генерирует недопустимый build.gradle, поскольку я получаю следующую ошибку:

FAILURE: Build failed with an exception.

* Where:
Build file 'C:\Users\fmate\code\example\openapi-java-client\build.gradle' line: 23

* What went wrong:
Could not compile build file 'C:\Users\fmate\code\example\openapi-java-client\build.gradle'.
> startup failed:
  build file 'C:\Users\fmate\code\example\openapi-java-client\build.gradle': 23: unexpected char: '\' @ line 23, column 35.
         main.java.srcDirs = ['src/main\java']

Очевидно, это не будет работать так, как вы хотели, поскольку это проблема самого плагина Gradle. Если вам просто нужно включить сгенерированный код в свой проект, просто включите сгенерированный код Java как часть вашего основного источника Java:

openApiGenerate {
    generatorName.set("java")
    inputSpec.set("$rootDir/specs/petstore.json")
    outputDir.set("$buildDir/openapi-java-client")
    apiPackage.set("org.openapi.example.api")
    invokerPackage.set("org.openapi.example.invoker")
    modelPackage.set("org.openapi.example.model")
}

tasks {
    compileJava {
        dependsOn(openApiGenerate)
    }
}

sourceSets {
    main {
        java {
            srcDir(files("${openApiGenerate.outputDir.get()}/src/main"))
        }
    }
}

Но при таком подходе вы столкнетесь с отсутствием импорта / зависимостей. Не похоже, что этот плагин предлагает возможность просто генерировать только модели / POJO, поэтому обновив свойство library до native и вручную добавив некоторые недостающие зависимости, все работает:

plugins {
    java
    id("org.openapi.generator") version "5.0.0-beta"
}

repositories {
    mavenCentral()
}

group = "io.mateo.test"

dependencies {
    implementation(platform("com.fasterxml.jackson:jackson-bom:2.11.1"))
    implementation("com.fasterxml.jackson.core:jackson-databind")
    implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
    implementation("org.openapitools:jackson-databind-nullable:0.2.1")
    implementation("com.google.code.findbugs:jsr305:3.0.2")
    implementation("io.swagger:swagger-core:1.6.2")
}

openApiGenerate {
    generatorName.set("java")
    inputSpec.set("$rootDir/specs/petstore.json")
    outputDir.set("$buildDir/openapi-java-client")
    apiPackage.set("org.openapi.example.api")
    invokerPackage.set("org.openapi.example.invoker")
    modelPackage.set("org.openapi.example.model")
    library.set("native")
    configOptions.put("dateLibrary", "java8")
}

tasks {
    compileJava {
        dependsOn(openApiGenerate)
    }
}

sourceSets {
    main {
        java {
            srcDir(files("${openApiGenerate.outputDir.get()}/src/main"))
        }
    }
}
person Francisco Mateo    schedule 26.07.2020

Вы не можете настроить его подобным образом, потому что build наверняка является выходным каталогом, который создаст циклическую ссылку. Лучше попробуйте добавить новый модуль и добавить этот плагин генератора в этот модуль. Если вы можете настроить другой модуль как outputDir, на него можно будет ссылаться.

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

Дело в том, что корневой проект всегда выполняется, в отличие от настроек модуля.

person Martin Zeitler    schedule 26.07.2020

Я только что ответил на очень похожий вопрос. Хотя мой ответ там не идеален, я лично все же предпочел бы подход, предложенный там - и как бы повторенный здесь:

Предлагаемый подход

Я бы держал сборки модулей, которые зависят от сгенерированного API, полностью отдельно от сборки, которая генерирует API. Единственной связью между такими сборками должно быть объявление зависимости. Это означает, что вам нужно будет вручную убедиться, что вы сначала создали проект создания API, а потом строить только зависимые проекты.

По умолчанию это будет означать также публикацию модуля API до создания зависимых проектов. Альтернативой этому по умолчанию может быть составные сборки Gradle - например, чтобы разрешить вы должны протестировать только что созданный API локально перед его публикацией. Однако перед созданием / запуском составной сборки вам придется вручную запускать API, генерирующий сборку каждый раз, когда изменяется документ OpenAPI.

Пример

Допустим, у вас есть проект A в зависимости от сгенерированного API. Его сборка Gradle будет содержать что-то вроде этого:

dependencies {
    implementation 'com.example:api:1.0'
}

Конечно, simple-java-app сборка, описанная в вопросе, должна быть адаптирована для создания модуля с этими координатами:

openApiGenerate {
    // …
    groupId = "com.example"
    id = "api"
    version = "1.0"
}

Перед запуском сборки A вам нужно сначала запустить

  1. ./gradlew openApiGenerate из вашего simple-java-app проекта.
  2. ./gradlew publish из каталога simple-java-app/build/openapi-java-client/.

Затем сборка A может получить опубликованную зависимость из репозитория публикации.

В качестве альтернативы вы можете отбросить шаг 2 локально и запустить сборку A с дополнительной опцией Gradle CLI:

./gradlew --include-build $path_to/simple-java-app/build/openapi-java-client/ …
person Chriki    schedule 30.12.2020