Kotlin Gradle Plugin 2.0.10-RC changed compileTestKotlin to depend on Jar - breaks my build

Hi all, I’m not sure if I should raise this here or as a YouTrack ticket, but I’ll start here, cause maybe somebody can help me, or explain what’s going on.

Basically, as of Kotlin Gradle Plugin 2.0.10-RC, the compileTestJava (I think) task depends on the jar task. However, I have an existing build where I have a custom task, which jar depends on, and my custom task depends on compileTestKotlin (which depends on compileTestJava). This is creating a circular dependency for my build, which means I can’t go past Kotlin Gradle Plugin 2.0.0.

I’ve created a reproducible example here: GitHub - Skater901/kotlin-plugin-task-dependency-change: Small reproducible example to show how Kotlin Gradle Plugin changed task dependencies in 2.0.10-RC

If you try to run the test task, it will fail with the circular dependency problem. If you instead change the Kotlin Gradle Plugin to version 2.0.0, the test task will work.

My question is: why was this change made, and is there anything I can do to undo it in my local build? I don’t understand why compiling test code depends on building a jar file.

For those wondering why my build works this way; I’m compiling a native binary using GraalVM, so I’m trying to reduce/eliminate dynamic reflection magic at runtime. I’m using Swagger annotations to document my Jakarta resources, and I want to generate my OpenAPI documentation at build time, and include it in my native binary. To do this, I have a test class that generates the OpenAPI file, and a custom Gradle task that runs this test class. The Gradle task has to run before the jar file is created, so that the OpenAPI file is included in the jar.

I can potentially move the code from the test class into the Gradle build file itself, but that seems kind of nasty.

I cannot tell for sure why they made this change, but it makes sense: the final artifact of the Java is JAR file. If they use the folders with class files in the CLASSPATH for tests, they would miss the final important step (creating JAR file) from testing.
You, on another hand, “hacking” the build process by using the tests to create the source code. How in your case you would test the source code (even though it is not Java code) you generated?
I can see 2 solutions:

  1. Change your task to generate OpenAPI doc to be a build task and not test. Then it will be executed before jar task
  2. Split your project in 2 modules: one builds and tests your main code, and another builds OpenAPI doc and combines it with stuff from another module into final JAR.
1 Like

I don’t think that’s always the case, though? Probably 99% of the time it is, but you don’t have to distribute your code inside a jar file.

I’m not sure what you mean by this. Creating the JAR is a function of the build tool (Gradle), and not something my automated tests have anything to do with.

I don’t test it. It’s not even code; it’s a JSON and YAML file. I just need to generate it to be included in the final build. I guess that sentence suggests that maybe it should be a build task and not a test class… I’ll consider refactoring it.

In that 1% cases how you planning to distribute tens, hundreds, or even thousands of .class files? By archiving them into single file. This is what JAR doing.

Exactly. This is what I try to say!

Well I have one project where I just download the source code and use Gradle to run the application on my server. :stuck_out_tongue:

So you compiling your application every time to run?! And may need to download half of Internet to get all dependencies?!
Why would you do that instead of distributing binary?..
Good I left 1% for that strange use case ;-D

FWIW, the way I fixed this was by simply making my generateOpenAPISpec task not be a dependency of the Jar task. Turns out I don’t need the spec to be included in the Jar, I only need the spec to be generated before the GraalVM native image build runs.

I tried making this a custom Gradle task, but as far as I can tell, there’s no way to do it. The nature of the Swagger library is using reflection to scan for resources in your class path, but Gradle tasks can’t access your source code for things like reflection, as far as I can work out. So I’ve left it as is; a “test” that produces an artifact that gets included in the native image. Only solution I can find. :slight_smile: