André Martins
04/07/2025, 2:06 PMtesting {
suites {
getByName<JvmTestSuite>("functionalTest") {
sources {
kotlin.srcDir(layout.buildDirectory.dir("generated/api/src/main/kotlin"))
}
dependencies {
...
}
}
}
}André Martins
04/07/2025, 2:06 PMAndré Martins
04/07/2025, 2:31 PMVampire
04/07/2025, 7:29 PMsrcDir directly. Given it properly declares its outputs, they become source files and all consumers automatically have the necessary task dependencies.Vampire
04/07/2025, 7:31 PMAndré Martins
04/08/2025, 9:49 AMAndré Martins
04/08/2025, 9:49 AMVampire
04/08/2025, 9:51 AMthe way Im doing worksIt might appear to work and maybe even work in some cases. But if you manually configured a path, it most probably does not cleanly work in all cases, and is discouraged bad practice. And I personally never had problems with IntelliJ and generated code when properly configuring it. 🙂 Mainly with Java, but I'd hope with Kotlin it is not much different.
André Martins
04/08/2025, 10:02 AMAndré Martins
04/08/2025, 10:04 AMInstead you should configure the task that generates the files asdirectly.srcDir
André Martins
04/08/2025, 10:04 AMAndré Martins
04/08/2025, 10:05 AMAndré Martins
04/08/2025, 10:06 AMVampire
04/08/2025, 10:35 AM-all distribution. There are 2 use-cases I know where it might help, one does not affect you and the other is a pretty rare edge case that most probably does not affect you. In all other cases it is just a waste of time, bandwidth, and disk space for each and everone and everything executing such a build.
Ok, so now seeing your MCVE it is exactly like I said.
It works "sometimes", but not all source consumers have a dependency on the generation task.
Only the compileKotlin and compileFunctionalTestKotlin have a dependency as you manually configured it.
That means any other consumer of source files (static code analysis tasks, sources jar task, ......) do not have a dependency.
If they happen to run before the generation task the files are missing or stale from a previous run, if they happen to run after, they might get the correct files accidentally.
Whenever you have a dependsOn where on the left-hand side is not a lifecycle task, that is a code smell and a strong sign that you are doing something wrong which is bad practice and discouraged.
Besides that, the MCVE is not V, the generation task fails with
Error resolving schema #/components/schemas/Orders
java.net.URISyntaxException: Illegal character in opaque part at index 2: D:\...\OASGeneratorWIP\app\specs\api-oas.yaml
Also, calling .get() on a Property at configuration time is a very bad idea.
It destroys the sense of lazy evaluation only at execution time. (line 32)
There it should probably be .map { it.asFile.absolutePath } instead and .asFile.absolutePath in the next line.
So using this patch:
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 2a5a268..31c4f69 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,5 +1,4 @@
import org.openapitools.codegen.languages.KotlinSpringServerCodegen
-import org.openapitools.generator.gradle.plugin.tasks.GenerateTask
plugins {
`common-kotlin`
@@ -29,8 +28,8 @@ openApiGenerate {
packageName = "<http://org.example.specfirst.app|org.example.specfirst.app>"
apiPackage = "<http://org.example.specfirst.app|org.example.specfirst.app>"
modelPackage = "org.example.specfirst.app.model"
- outputDir = layout.buildDirectory.dir("generated/openapi").get().toString()
- inputSpec = layout.projectDirectory.file("specs/api-oas.yaml").toString()
+ outputDir = layout.buildDirectory.dir("generated/openapi").map { it.asFile.absolutePath }
+ inputSpec = layout.projectDirectory.file("specs/api-oas.yaml").asFile.absolutePath
configOptions = mapOf(
KotlinSpringServerCodegen.INTERFACE_ONLY to "true",
KotlinSpringServerCodegen.USE_TAGS to "true",
@@ -44,28 +43,20 @@ openApiGenerate {
kotlin.sourceSets {
main {
kotlin {
- srcDir(layout.buildDirectory.dir("generated/openapi/src/main/kotlin"))
+ srcDir(tasks.openApiGenerate)
}
}
functionalTest {
kotlin {
- srcDir(layout.buildDirectory.dir("generated/openapi/src/main/kotlin"))
+ srcDir(tasks.openApiGenerate)
}
}
}
-tasks.compileKotlin {
- dependsOn(tasks.withType<GenerateTask>())
-}
-
-tasks.compileFunctionalTestKotlin {
- dependsOn(tasks.withType<GenerateTask>())
-}
-
testing.suites {
getByName(TestingSuites.FUNCTIONAL_TEST) {
dependencies {
}
}
-}
\ No newline at end of file
+}
does fix the get and dependsOn stuff and it works exactly like you are seeing now, it works in main source set but not in the test source set.
But having said all that, your main problem is, that IntelliJ can use a given source root only once.
As you define the same directory as source directory for both source sets, you waste time by compiling those sources twice.
But more importantly, as I said, IntelliJ can only add a directory to one module as source set but in your setup it would need to add it to two modules and that is simply not supported by IntelliJ as this also usually does not make much sense.
More typically you have it in one place and depend on it from the other place or the other two places.Vampire
04/08/2025, 10:55 AMdiff --git a/app/.openapi-generator-ignore b/app/.openapi-generator-ignore
new file mode 100644
index 0000000..dc40c93
--- /dev/null
+++ b/app/.openapi-generator-ignore
@@ -0,0 +1,2 @@
+/build/generated/openapi/**
+!build/generated/openapi/org/**
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 2a5a268..896b8af 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,3 +1,4 @@
+import org.gradle.api.tasks.PathSensitivity.NONE
import org.openapitools.codegen.languages.KotlinSpringServerCodegen
import org.openapitools.generator.gradle.plugin.tasks.GenerateTask
@@ -24,6 +25,8 @@ dependencies {
runtimeOnly(libs.logback)
}
+val openApiGeneratorIgnoreFile = layout.projectDirectory.file(".openapi-generator-ignore")
+
openApiGenerate {
generatorName = "kotlin-spring"
packageName = "<http://org.example.specfirst.app|org.example.specfirst.app>"
@@ -32,6 +35,7 @@ openApiGenerate {
outputDir = layout.buildDirectory.dir("generated/openapi").get().toString()
inputSpec = layout.projectDirectory.file("specs/api-oas.yaml").toString()
configOptions = mapOf(
+ "sourceFolder" to "",
KotlinSpringServerCodegen.INTERFACE_ONLY to "true",
KotlinSpringServerCodegen.USE_TAGS to "true",
"library" to KotlinSpringServerCodegen.SPRING_BOOT,
@@ -39,6 +43,19 @@ openApiGenerate {
KotlinSpringServerCodegen.DOCUMENTATION_PROVIDER to "none",
KotlinSpringServerCodegen.ANNOTATION_LIBRARY to "none",
)
+ generateApiDocumentation = false
+ generateApiTests = false
+ generateModelDocumentation = false
+ generateModelTests = false
+ ignoreFileOverride = openApiGeneratorIgnoreFile.asFile.absolutePath
+}
+
+//work-around for <https://github.com/OpenAPITools/openapi-generator/issues/10214>
+tasks.openApiGenerate {
+ inputs
+ .files(openApiGeneratorIgnoreFile)
+ .withPathSensitivity(NONE)
+ .withPropertyName("openApiGeneratorIgnoreFile")
}
kotlin.sourceSets {André Martins
04/08/2025, 11:01 AMBesides that, the MCVE is not V, the generation task fails with
```Error resolving schema #/components/schemas/Orders
java.net.URISyntaxException: Illegal character in opaque part at index 2: D:\...\OASGeneratorWIP\app\specs\api-oas.yaml```I don't have that issue, do you get it when running
gradle build?
Regarding the main issue I understand the problem is with Intellij, although was wondering if there is a correct way of doing this via gradle that would end up being recognised by IntelliJ.André Martins
04/08/2025, 11:03 AMVampire
04/08/2025, 11:35 AMI don't have that issue,Because you probably are on non-Windoze I get it on
gw openApiGenerateVampire
04/08/2025, 11:36 AMRegarding the main issue I understand the problem is with Intellij, although was wondering if there is a correct way of doing this via gradle that would end up being recognised by IntelliJ.As I said, do not use the same source dir for two source sets. That will also cause double compilation of the files. You could for example add another source set and then depend on that source set from the two others instead.
André Martins
04/08/2025, 1:00 PMnon-Windoze?André Martins
04/08/2025, 1:01 PMVampire
04/08/2025, 1:16 PMSorry,I guess you use Linux or macOS. On Linux-environment it worked, it just failed on Windows for me. But anyway, I was able to mitigate it, so 🤷♂️non-Windoze
André Martins
04/08/2025, 3:43 PMAndré Martins
04/08/2025, 3:45 PMAndré Martins
04/08/2025, 4:14 PM