Ukeshava
Ukeshava

Reputation: 1

classes not visible to gradle task swagger when using kongchen swagger-maven-plugin

When performing gradle clean and then gradle swagger a ClassNotFoundException is thrown. If gradle swagger is then run again (basically after the api build is done in previous run), it works fine.

build.gradle looks as below:

buildscript {
    repositories {
        maven { url hydraMavenRepo }
        maven { url hydraPluginsRepo }
    }
    dependencies {
        classpath "com.github.kongchen:swagger-maven-plugin:3.1.4"
    }
}

apply plugin: 'java'

configurations {
    addclasspath
}

dependencies {
    addclasspath files(project(':api:desktop-api').configurations['runtime'].files)
    addclasspath files(project(':api:desktop-api').sourceSets['main'].output)
    addclasspath files(project(':api:desktop-api').sourceSets.main.output.classesDir)

    runtime project(':api:desktop-api')
}

sourceSets {
    main {
        runtimeClasspath += files(project(':api:desktop-api').sourceSets['main'].output)
        runtimeClasspath += files(project(':api:desktop-api').sourceSets['main'].output.classesDir)
        runtimeClasspath += files(project(':api:desktop-api').configurations['runtime'].files)
    }
}


import com.github.kongchen.swagger.docgen.mavenplugin.ApiDocumentMojo
import com.github.kongchen.swagger.docgen.mavenplugin.ApiSource
import io.swagger.models.Info

task swagger(dependsOn: [':api:desktop-api:build']) {
    doLast {
        logger.info 'Swagger GenDoc...'
        project.file(reportsDir).mkdirs()

        // a trick to have all needed classes in the classpath
        def customClassLoader = new GroovyClassLoader()

        buildscript.configurations.classpath.each {
            //println it.toURI().toURL()
            customClassLoader.addURL(it.toURI().toURL())
        }

        configurations.addclasspath.each {
            customClassLoader.addURL(it.toURI().toURL())
        }

        // the same settings as in the swagger-maven-example/pom.xml
        final ApiDocumentMojo mavenTask = Class.forName('com.github.kongchen.swagger.docgen.mavenplugin.ApiDocumentMojo', true, customClassLoader).newInstance(
                apiSources: [
                        new ApiSource(
                                springmvc: false,
                                locations: ['com/vmware/vdi/hydra'],
                                schemes: ['http', 'https'],
                                host: 'vmware.com',
                                basePath: '/api',
                                info: new Info(
                                        title: "Hydra DS-REST API's",
                                        version: 'v100',
                                        description: "Hydra DS-REST API's",
                                ),
                                swaggerDirectory: reportsDir
                        )
                ]
        )
        mavenTask.execute()
        logger.info 'Swagger GenDoc task is completed'
    }
}

Upvotes: 0

Views: 1277

Answers (2)

Ukeshava
Ukeshava

Reputation: 1

buildscript.classloader is what I was looking for.

Below is the code that works:

buildscript {
    repositories {
        maven { url mavenRepo }
    }
    dependencies {
        classpath "com.github.kongchen:swagger-maven-plugin:3.1.4"
    }
}

import com.github.kongchen.swagger.docgen.mavenplugin.ApiDocumentMojo
import com.github.kongchen.swagger.docgen.mavenplugin.ApiSource
import io.swagger.models.Info


task swagger(dependsOn: ':api:build') {
    doLast {
        logger.info 'Swagger GenDoc...'
        project.file(<dir>).mkdirs()

        FileCollection apiRuntimeFiles = files(project(':api').configurations['runtime'].files)
        apiRuntimeFiles.each {
            buildscript.classLoader.addURL(it.toURI().toURL())
        }

        FileCollection apiClassFiles =files(project(':api').sourceSets['main'].output)
        apiClassFiles.each {
            buildscript.classLoader.addURL(it.toURI().toURL())
        }

        final ApiDocumentMojo mavenTask = Class.forName('com.github.kongchen.swagger.docgen.mavenplugin.ApiDocumentMojo', true, buildscript.classLoader).newInstance(
                apiSources: [
                        new ApiSource(
                                springmvc: false,
                                locations: ['<loc>'],
                                schemes: ['http', 'https'],
                                host: '<host>',
                                basePath: '/api',
                                info: new Info(
                                        title: "REST API's",
                                        version: 'v1',
                                        description: "REST API's",
                                ),
                                swaggerDirectory: <dir>
                        )
                ]
        )
        mavenTask.execute()
        logger.info 'Swagger GenDoc task is completed'
    }
}

Upvotes: 0

Vampire
Vampire

Reputation: 38669

You have several flaws in your build script.

You should not depend on built things in build script dependencies. This is a hen and egg problem. You need to execute the build to get the classes that are necessary to execute the build. This cannot work reliably, if at all.

Instead you should declare them as dependencies outside the buildscript block. The buildscript block is only for dependencies that are needed by your build script to run itself, like Gradle Tasks and Gradle Plugins or classes you use during the build, like the swagger-maven-plugin stuff which is correct in the buildscript block.

Besides that, you execute part of your swagger stuff (the instanciation, execution and printing) during the configuration phase instead of during the execution phase. Everything you do in a task closure, but outside any doFirst or doLast blocks is run during the configuration phase, when the build is configured and thus always, no matter what tasks you actually want to execute and no matter whether the task may already be up-to-date or not. For the up-to-date check to work and save your time you need to declare all inputs like files and properties that might change between executions and all outputs that you generate, then Gradle can do its magic to only execute the task when actually necessary.

Also you should not use println in build scripts. That is like using System.out.println in Java programs. Instead you should use the provided logging facility directly, e. g. doing logger.info 'Swagger GenDoc task is completed'.

Upvotes: 0

Related Questions