javaspring-bootkotlingradlequerydsl

How to set dependency for gradle task `kaptGenerateStubsKotlin` to `openApiGenerate` kotlin kapt


Rewriting an API program from java to kotlin.

I am generating some models from openAPI spec file during build process using openapi generator. Those models are also used inside the rest api program and by querydsl and jpa repository.

build.gradle File:

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
buildscript {
    ext{
        kotlinVersion = '1.9.23'
    }
}

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.2.3'
    id "org.openapi.generator" version "7.2.0"
    id 'org.jetbrains.kotlin.jvm' version "$kotlinVersion"
    id 'org.jetbrains.kotlin.plugin.spring' version "$kotlinVersion"
    id "org.jetbrains.kotlin.kapt" version "$kotlinVersion"
    id 'jacoco'
    id "com.gorylenko.gradle-git-properties" version "2.4.1"
    id 'com.adarshr.test-logger' version '4.0.0'
    id 'org.cyclonedx.bom' version '1.8.2'
}

apply plugin: 'io.spring.dependency-management'

group = 'com.test'
version = '0.11.1'
description = 'Restapi'

java {
    sourceCompatibility = JavaVersion.VERSION_21
    targetCompatibility = JavaVersion.VERSION_21
}

repositories {
    mavenCentral()
    gradlePluginPortal()
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
  }
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.security:spring-security-oauth2-resource-server'
    implementation 'org.springframework.security:spring-security-oauth2-jose'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.springframework.kafka:spring-kafka'
    implementation 'org.jetbrains.kotlin:kotlin-reflect'
    implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'
    implementation 'org.openapitools:jackson-databind-nullable:0.2.6'
    implementation 'com.querydsl:querydsl-jpa::jakarta'
    implementation 'com.querydsl:querydsl-apt'
    implementation 'org.liquibase:liquibase-core'
    implementation "com.google.guava:guava:32.1.2-jre"
    implementation 'org.apache.tika:tika-core:2.9.0'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    annotationProcessor "com.querydsl:querydsl-apt::jakarta"
    kapt "com.querydsl:querydsl-apt::jakarta"
    annotationProcessor "jakarta.persistence:jakarta.persistence-api"
    runtimeOnly 'org.postgresql:postgresql'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.boot:spring-boot-starter-webflux'
    testImplementation 'org.springframework.security:spring-security-test'
    testImplementation 'org.springframework.kafka:spring-kafka-test'
    testImplementation 'org.springframework.boot:spring-boot-testcontainers'
    testImplementation 'org.testcontainers:junit-jupiter'
    testImplementation 'org.testcontainers:postgresql'
    testImplementation 'org.testcontainers:kafka'
}

tasks.withType(KotlinCompile) {
  kotlinOptions {
    freeCompilerArgs += '-Xjsr305=strict'
    jvmTarget = '21'
  }
}

openApiGenerate {
    generatorName = "kotlin-spring"
    library = "spring-boot"
    groupId = "${project.group}"
    inputSpec = "$rootDir/api/restella-openapi.yaml"
    apiPackage = "${project.group}.${project.name}.generated.api"
    modelPackage = "${project.group}.${project.name}.generated.model"
    ignoreFileOverride = "$rootDir/.openapi-generator-ignore"
    configOptions = [
        interfaceOnly: "true",
        useTags: "true",
        documentationProvider: "springdoc",
        useSpringBoot3: "true",
        enumPropertyNaming: "UPPERCASE",
        generatedConstructorWithRequiredArgs : "false",
        additionalModelTypeAnnotations: "@lombok.AllArgsConstructor;@lombok.NoArgsConstructor"
    ]
}

openApiGenerators {
    include = [
        'stable'
        ]
}

sourceSets {
    main {
        kotlin {
            srcDirs += "$buildDir/generate-resources/main/src/main/kotlin"
        }
    }
}

compileJava.dependsOn tasks.openApiGenerate, tasks.compileKotlin
compileKotlin.dependsOn tasks.openApiGenerate

kapt {
    javacOptions {
        option("querydsl.entityAccessors", true)
    }
    arguments {
        arg("plugin", "com.querydsl.apt.jpa.JPAAnnotationProcessor")
    }
}

tasks.named('test') {
  useJUnitPlatform()
}

I get the following error when running gradle build

> Task :openApiGenerate FAILED

FAILURE: Build failed with an exception.

* What went wrong:
A problem was found with the configuration of task ':openApiGenerate' (type 'GenerateTask').
  - Gradle detected a problem with the following location: '/workspaces/Restella/build/generate-resources/main'.
    
    Reason: Task ':kaptGenerateStubsKotlin' uses this output of task ':openApiGenerate' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed.
    
    Possible solutions:
      1. Declare task ':openApiGenerate' as an input of ':kaptGenerateStubsKotlin'.
      2. Declare an explicit dependency on ':openApiGenerate' from ':kaptGenerateStubsKotlin' using Task#dependsOn.
      3. Declare an explicit dependency on ':openApiGenerate' from ':kaptGenerateStubsKotlin' using Task#mustRunAfter.
    
    For more information, please refer to https://docs.gradle.org/8.5/userguide/validation_problems.html#implicit_dependency in the Gradle documentation.

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.

BUILD FAILED in 1s
5 actionable tasks: 5 executed

Adding task dependency also get error

I tried to add dependency for kaptGenerateStubsKotlin:

tasks.named('kaptGenerateStubsKotlin').configure {
    dependsOn 'openApiGenerate'
}

But I get error:

FAILURE: Build completed with 2 failures.

1: Task failed with an exception.
-----------
* Where:
Build file '/workspaces/restapi/build.gradle' line: 134

* What went wrong:
A problem occurred evaluating root project 'restella'.
> Task with name 'kaptGenerateStubsKotlin' not found in root project 'restella'.

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.
==============================================================================

2: Task failed with an exception.
-----------
* Where:
Build file '/workspaces/restapi/build.gradle' line: 134

* What went wrong:
A problem occurred evaluating root project 'restella'.
> Task with name 'kaptGenerateStubsKotlin' not found in root project 'restella'.

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.
==============================================================================

BUILD FAILED in 567ms

What is wrong here? How can I update the build.gradle to use openapi generate, querydsl as I was with java?


Solution

  • I confess it's a mystery to me why your explicit task dependency isn't working.

    You could try the following:

    import org.jetbrains.kotlin.gradle.internal.KaptGenerateStubsTask
    
    tasks.withType(KaptGenerateStubsTask).configureEach {
        dependsOn 'openApiGenerate'
    }
    

    That will add the dependency as and when any such Kapt task is added to the project so will not fail if it cannot find a Kapt task of a specific name.