簡體   English   中英

使用 swagger codegen for openapi 3.0 生成代碼時出現 NullPointer 異常

[英]NullPointer exception while generating code using swagger codegen for openapi 3.0

通過 swagger codegen 生成代碼時遇到 NullPointer 問題。 我是 gradle 的新手,並更新了 build.gradle 以反映為給定 API 規范生成代碼所需的最新更改。

請提供您的寶貴意見。

我的 build.gradle 如下圖所示:

import io.swagger.codegen.v3.CodegenConfigLoader
import io.swagger.codegen.v3.DefaultGenerator
import io.swagger.codegen.v3.ClientOptInput
import io.swagger.codegen.v3.ClientOpts
import io.swagger.v3.parser.OpenAPIV3Parser

buildscript {
    ext {
        springBootVersion = '2.0.5.RELEASE'
        jacocoWorkspaceDirectory = "/jacoco/"
    }
    repositories {
        mavenLocal()
        maven { url "http://repo.maven.apache.org/maven2" }
    }
    dependencies {
        classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"
        classpath group: "io.spring.gradle", name: "dependency-management-plugin", version: "1.0.6.RELEASE"
        classpath 'co.bambo.sonar:bambo-sonar-gradle-plugin:2.7.1.RELEASE'
        classpath group: "org.unbroken-dome.gradle-plugins", name: "gradle-testsets-plugin", version: "1.4.2"
        classpath('io.swagger.codegen.v3:swagger-codegen-maven-plugin:3.0.16')
        classpath("io.swagger.core.v3:swagger-core:2.1.1")
    }
}

apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'maven-publish'
apply plugin: "io.spring.dependency-management"
apply plugin: "org.springframework.boot"
apply plugin: 'bambo-sonar'
apply plugin: "jacoco"
apply plugin: "findbugs"
apply plugin: "checkstyle"
apply plugin: "pmd"
apply plugin: 'org.unbroken-dome.test-sets'


project.buildDir = 'target'

ext {
    appName = 'school-management'
    apiPackage = 'co.bambo.school.management.generated.api'
    modelPackage = 'co.bambo.school.management.generated.model'
    swaggerFile = "${rootDir}/src/main/resources/schoolmanagement.v1.yaml"
    swaggerBuildDir = "${project.buildDir}/" + appName
}


// NOTE :-> Following are to be included as and when required.
// These variables are defined for the purpose of exclusion from the sonar scan. Packages mentioned will be exluded
// from Sonar Scans.
def excludeschoolmanagementConstants = "src/main/java/co/bambo/school/management/constants/schoolmanagementConstants.java"
def excludeCaasConstants = "src/main/java/co/bambo/school/management/pcf/constants/CaasConstants.java"

sourceCompatibility = 1.8
targetCompatibility = 1.8

group = 'co.bambo.schoolmanagement'
version = '1.0.0-SNAPSHOT'

tasks.withType(JavaCompile) {
    options.encoding = 'UTF-8'
}

repositories {
    mavenLocal()
    maven { url "http://repo.maven.apache.org/maven2" }
}

configurations {
    testUtilCompile.extendsFrom testImplementation
    testUtilRuntime.extendsFrom testRuntime
}

sourceSets {
    testUtil {
        java {
            srcDir 'src/test-util/java'
        }
    }
}

testSets {
    funcTest { dirName = "func-test" }
}


// PLUGIN CONFIGs
springBoot {
    mainClassName = 'co.bambo.school.management.schoolmanagementApplication'
    buildInfo()
}

bootJar {
    baseName = 'school-management'
    destinationDir = project.buildDir
    archiveName = 'school-management.jar'
}

// FIXME - IN FUTURE WE NEED TO MAKE THIS to Zero.
checkstyle {
    maxErrors = 70
    maxWarnings = 70
    toolVersion = 8.17
}

[checkstyleMain, checkstyleTest].each { task ->
    task.logging.setLevel(LogLevel.LIFECYCLE)
    // FIXME -  This is to be updated with False.
    task.ignoreFailures = true
}

findbugs {
    toolVersion = "3.0.1"
    sourceSets = [sourceSets.main]
    // FIXME - Make this false.
    ignoreFailures = true
    effort = "max"
    reportLevel = "medium"
    excludeFilter = file("$rootDir/config/findbugs/exclude.xml")
}

pmd {
    toolVersion = "5.6.1"
    ignoreFailures = true
    sourceSets = [sourceSets.main]
    reportsDir = file("${project.buildDir}/reports/pmdTest")
    ruleSets = [
            'java-basic'
    ]
}

tasks.withType(FindBugs) {
    reports {
        xml.enabled = false
        html.enabled = true
    }
}

tasks.withType(Pmd) {
    reports {
        xml.enabled = false
        html.enabled = true
    }
}


sonarqube {
    properties {
        property "sonar.projectName", "school-management"
        property "sonar.projectKey", "school-management"
        property "sonar.jacoco.reportPath", "build/jacoco/test.exec"
        property "sonar.junit.reportPaths", "build/test-results/test"
        property "sonar.host.url", "https://fusion.bambo.int/sonar"
        property "sonar.gateId", "307"
        property "sonar.projectDescription", "school management microservice."
        property "sonar.skip.qualityGate", "false"
        property "sonar.exclusions", [excludeschoolmanagementConstants, excludeCaasConstants]
    }
}

// Actual task for generating the server
task generateServer {
    doLast {
        def openAPI = new OpenAPIV3Parser().read(rootProject.swaggerFile.toString(), null, null)
        def clientOptInput = new ClientOptInput().openAPI(openAPI)
        def codeGenConfig = CodegenConfigLoader.forName('spring')
        codeGenConfig.setApiPackage(rootProject.ext.apiPackage)            // Package to be used for the API interfaces
        codeGenConfig.setModelPackage(rootProject.ext.modelPackage)        // Package to be used for the API models
        codeGenConfig.setInputSpec(rootProject.ext.swaggerFile.toString()) // The swagger API file
        codeGenConfig.setOutputDir(rootProject.ext.swaggerBuildDir)
        // The output directory, user-service-contract/build/user-service-server/
//        codegenConfig.addSystemProperty("models", "");
//        codegenConfig.addSystemProperty("apis", "");

        def clientOps = new ClientOpts()
        clientOps.setProperties([
                'dateLibrary'  : 'java8', // Date library to use
                'useTags'      : 'true',  // Use tags for the naming
                'interfaceOnly': 'false'// Generating the Controller API interface and the models only
        ])
        clientOptInput.setOpts(clientOps)
        def generator = new DefaultGenerator().opts(clientOptInput)
        generator.generate() // Executing the generation
    }
}

compileJava {
    dependsOn generateServer
}

build {
    dependsOn generateServer
}

// ---- PLUGIN CONFIG ENDs


dependencyManagement {
    imports {
        mavenBom "org.springframework.boot:spring-boot-dependencies:$springBootVersion"
    }
}

funcTest {
    doFirst {
        jacoco {
            destinationFile = file("${buildDir}" + jacocoWorkspaceDirectory + "test.exec")
        }
    }

    dependsOn cleanTest
    dependsOn compileTestUtilJava
    dependsOn cleanJacocoTestReport
    dependsOn cleanJacocoTestCoverageVerification
    finalizedBy jacocoTestReport
    finalizedBy jacocoTestCoverageVerification
    environment SPRING_PROFILES_ACTIVE: environment.SPRING_PROFILES_ACTIVE ?: "local"
}

dependencies {
    // Spring specific dependencies
    implementation('org.springframework:spring-tx')
    implementation('org.springframework:spring-core')
    implementation('org.springframework:spring-context')
    implementation('org.springframework:spring-beans')
    implementation('org.springframework:spring-expression')
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-actuator'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-aop'
    implementation group: 'org.springframework.retry', name: 'spring-retry'

    implementation group: 'org.springframework.boot', name: "spring-boot-starter-data-jpa"

    // Spring cloud
    // Upgraded springcloud-starter-vault from 2.0.0.RC1 to 2.0.1.RELEASE.
    implementation group: 'org.springframework.cloud', name: 'spring-cloud-starter-vault-config', version: '2.0.1.RELEASE'
    implementation group: 'io.pivotal.spring.cloud', name: 'spring-cloud-services-starter-config-client', version: '2.0.1.RELEASE'
    // Upgraded "spring-cloud-starter-bus-amqp" following from 2.0.0.RC1 to 2.0.1.RELEASE
    implementation group: 'org.springframework.cloud', name: 'spring-cloud-starter-bus-amqp', version: '2.0.1.RELEASE'

    // SWagger dependencies
    implementation group: 'io.swagger', name: 'swagger-parser', version: '1.0.23'
    implementation group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
    implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'
    implementation group: 'com.atlassian.oai', name: 'swagger-request-validator-core', version: '1.3.9'

    // Apache - Commons
    implementation group: 'commons-io', name: 'commons-io', version: '2.6'

    // Oracle dependencies
    implementation group: 'com.oracle', name: 'ojdbc7', version: '12.1.0'

    //2nd level cache dependency
    implementation group: 'org.hibernate', name: 'hibernate-ehcache'

    // Logback
    implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3'
    implementation group: 'ch.qos.logback', name: 'logback-core', version: '1.2.3'

    implementation group: 'org.apache.camel', name: 'camel-jsonpath', version: '2.22.0'
    implementation group: 'com.google.gdata', name: 'core', version: '1.47.1'
    implementation group: 'com.google.guava', name: 'guava', version: '20.0'

    // FIXME - Eventually phase - out this Mapper
    implementation group: 'ma.glasnost.orika', name: 'orika-core', version: '1.5.4'

    // JSON
    implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-xml', version: '2.8.10'
    implementation group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1.1'

    // Mapstruct
    implementation 'org.mapstruct:mapstruct:1.3.0.Final'
    implementation 'org.mapstruct:mapstruct-processor:1.3.0.Final'

    implementation group: 'ch.qos.logback.contrib', name: 'logback-json-classic', version: '0.1.5'
    implementation group: 'ch.qos.logback.contrib', name: 'logback-jackson', version: '0.1.5'

    testImplementation "junit:junit:4.12"
    testImplementation group: "org.springframework.boot", name: "spring-boot-starter-test"
    testImplementation group: 'com.github.tomakehurst', name: 'wiremock', version: '2.21.0'

    testUtilCompile sourceSets.main.output
    funcTestCompile sourceSets.testUtil.output
}

我在這一行遇到NullPointer問題def generator = new DefaultGenerator().opts(clientOptInput)

Update-1我理解這個問題對於 Java 中的 NullPointer 異常來說似乎很容易。 但是相信我,我無法在 build.gradle 中弄清楚為什么它會失敗,因為它甚至沒有顯示正確的錯誤消息,說明缺少什么。 下面顯示的消息是我所得到的。 即使調試 groovy 腳本也無濟於事。

Execution failed for task ':generateServer'.
> java.lang.NullPointerException (no error message)

Update-2我剛剛在 DefaultGenerator.java 的第 77 行看到了這一行。 這是我得到 NullPointerException this.config.additionalProperties().putAll(opts.getOpts().getProperties());

我不確定參數中缺少什么。 我正在傳遞opts並且getOpts()也在填充屬性文件。

使用 gradle 4.9 版。

好吧,我想通了,這在理解和代碼中也是一個愚蠢的錯誤。

在調試和瀏覽swagger-codegen代碼后,我才知道這個錯誤。 我意識到生成代碼需要配置,基於此配置指定它正在生成代碼。 我正在生成基於spring的 CodeGenConfiguration,但我沒有將它傳遞到 clientOptInput。 我的理解是錯誤的,我認為它會加載 CodeGenConfig 的類(它確實加載了它),就是這樣。 但是,您還需要將其傳遞給clientOptInput變量。

def codeGenConfig = CodegenConfigLoader.forName('spring')
clientOptInput.setConfig(codeGenConfig)

因為, DefaultGenerator.java的代碼如下:

    @Override
    public Generator opts(ClientOptInput opts) {
        this.opts = opts;
        this.openAPI = opts.getOpenAPI();
        this.config = opts.getConfig();

我需要將它設置為ClientOptInput實例。 這就是原因。 為像我這樣犯錯的人發帖:) :)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM