How to access Kotlin source set directory using the Kotlin DSL?

Hello!

I am working on a project using both Groovy (Spock) and Kotlin for tests. I need to share some test code that is written in Kotlin.

Gradle 6.1 added the ability to define the compilation order between languages, as explained here. That’s exactly what I need.

When I adapt this to my needs, I get that (in Groovy):

tasks.named('compileTestGroovy') {
    classpath += files(sourceSets.test.kotlin.classesDirectory)
}

But I am using the Kotlin DSL and I am not able to write this in Kotlin.

sourceSets.test is a NamedDomainObjectProvider<SourceSet> so I have to add .get(). Ok, now I get a SourceSet.

SourceSet does not have any getKotlin() method or something like that (not surprising since it only works for Java by default). It also does not seem to have a getByName() or something like that to access the kotlin source set directory.

// How to access to the Koltin classes directory? This does not compile
tasks.compileTestGroovy {
    classpath += files(sourceSets.test.get().kotlin.classesDirectory)
}

I don’t know what the Groovy DSL magic does to access the kotlin source set container.

Could someone help me solve this issue?

Note that I found a temporary workaround by using the hard coded path:

tasks.compileTestGroovy {
    classpath += files("${buildDir}/classes/kotlin/test")
}

Thanks a lot, have a nice day!

It’s just inheritance. Since Groovy is a dynamic language, it doesn’t matter that the type you have a reference to is just a SourceSet. Once you apply the Kotlin plugin, it adds a convention, and you actually have an implementation type that implements KotlinSourceSet. In the Kotlin DSL, you need to get ahold of a strongly typed reference to the KotlinSourceSet instead of the just the SourceSet.

Thanks for your answer @jjustinic!

It does not seem to be inheritance. In my case, I use both Kotlin and Groovy and they are independent. As there is no multiple inheritance in Java, I don’t know how this could be done using inheritance.

Based on your suggestion, I looked for KotlinSourceSet and I found how to access to it.

Gradle generally uses extensions instead of inheritance. But there is no extension called kotlin. After investigation, I found this issue in which I learnt that it is not an extension but a convention.

I could access to the Kotlin SourceDirectorySet with this code:

val SourceSet.kotlin: SourceDirectorySet get() = this.withConvention(KotlinSourceSet::class) { kotlin }

tasks.compileTestGroovy {
    classpath += files(sourceSets.test.get().kotlin.classesDirectory)
}

I now have another issue but it is no longer related to the Kotlin DSL.

I get this error:

Could not determine the dependencies of task ‘:compileTestGroovy’.
> Cannot query the value of this property because it has no value available.

I tried with the Groovy DSL and I got exactly the same error.

It sounds like the kotlin.classesDirectory which is a Provider<Directory> is not defined.

I tried to invert it as shown in the Gradle 6.1 release notes (Kotlin depending on Groovy) and it works.
sourceSets.test.groovy.classesDirectory is defined, sourceSets.test.kotlin.classesDirectory is not.

I don’t know how to solve this issue. I will investigate that but if someone knows what to do, please let me know.

withConvention is deprecated, use this:

val SourceSet.kotlin: SourceDirectorySet
    get() = project.extensions.getByType<KotlinJvmProjectExtension>().sourceSets.getByName(name).kotlin

kudos to Martin Bonnin