Introduce Java support in JVM MPP targets (KT-26256)
Deprecate the `jvmWithJava` preset, add warning. Add a function `withJava()` to JVM MPP targets which applies the 'java' plugin and sets up the Kotlin & Java interoperation. Issue #KT-26256 Fixed Signed-off-by: Sergey Igushkin <hotkeytlt@gmail.com>
This commit is contained in:
+119
-38
@@ -5,11 +5,13 @@
|
||||
package org.jetbrains.kotlin.gradle
|
||||
|
||||
import org.jetbrains.kotlin.gradle.plugin.ProjectLocalConfigurations
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmWithJavaTargetPreset
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeOutputKind
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.UnusedSourceSetsChecker
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.METADATA_CONFIGURATION_NAME_SUFFIX
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.SourceSetConsistencyChecks
|
||||
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
|
||||
import org.jetbrains.kotlin.gradle.util.*
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
@@ -299,52 +301,131 @@ class NewMultiplatformIT : BaseGradleIT() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testJvmWithJavaEquivalence() = with(Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")) {
|
||||
lateinit var classesWithoutJava: Set<String>
|
||||
fun testJvmWithJavaEquivalence() = doTestJvmWithJava(testJavaSupportInJvmTargets = false)
|
||||
|
||||
fun getFilePathsSet(inDirectory: String): Set<String> {
|
||||
val dir = projectDir.resolve(inDirectory)
|
||||
return dir.walk().filter { it.isFile }.map { it.relativeTo(dir).path.replace('\\', '/') }.toSet()
|
||||
}
|
||||
@Test
|
||||
fun testJavaSupportInJvmTargets() = doTestJvmWithJava(testJavaSupportInJvmTargets = true)
|
||||
|
||||
build("assemble") {
|
||||
assertSuccessful()
|
||||
classesWithoutJava = getFilePathsSet("build/classes")
|
||||
}
|
||||
private fun doTestJvmWithJava(testJavaSupportInJvmTargets: Boolean) =
|
||||
with(Project("sample-lib", GradleVersionRequired.AtLeast("5.0"), "new-mpp-lib-and-app")) {
|
||||
lateinit var classesWithoutJava: Set<String>
|
||||
|
||||
gradleBuildScript().modify {
|
||||
it.replace("presets.jvm", "presets.jvmWithJava").replace("jvm(", "targetFromPreset(presets.jvmWithJava, ")
|
||||
}
|
||||
fun getFilePathsSet(inDirectory: String): Set<String> {
|
||||
val dir = projectDir.resolve(inDirectory)
|
||||
return dir.walk().filter { it.isFile }.map { it.relativeTo(dir).invariantSeparatorsPath }.toSet()
|
||||
}
|
||||
|
||||
projectDir.resolve("src/main/java").apply {
|
||||
mkdirs()
|
||||
mkdir()
|
||||
// Check that Java can access the dependencies (kotlin-stdlib):
|
||||
resolve("JavaClassInJava.java").writeText("""
|
||||
package com.example.lib;
|
||||
import kotlin.sequences.Sequence;
|
||||
class JavaClassInJava {
|
||||
Sequence<String> makeSequence() { throw new UnsupportedOperationException(); }
|
||||
build("assemble") {
|
||||
assertSuccessful()
|
||||
classesWithoutJava = getFilePathsSet("build/classes")
|
||||
}
|
||||
|
||||
gradleBuildScript().modify {
|
||||
if (testJavaSupportInJvmTargets) {
|
||||
it + "\nkotlin.jvm(\"jvm6\").${KotlinJvmTarget::withJava.name}()"
|
||||
} else {
|
||||
it.replace("presets.jvm", "presets.jvmWithJava").replace("jvm(", "targetFromPreset(presets.jvmWithJava, ")
|
||||
}.plus(
|
||||
"\n" + """
|
||||
buildscript {
|
||||
repositories {
|
||||
maven { url 'https://plugins.gradle.org/m2/' }
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.github.jengelman.gradle.plugins:shadow:5.0.0'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.github.johnrengelman.shadow'
|
||||
apply plugin: 'application'
|
||||
|
||||
mainClassName = 'com.example.lib.CommonKt'
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
fun javaSourceRootForCompilation(compilationName: String) =
|
||||
if (testJavaSupportInJvmTargets) "src/jvm6${compilationName.capitalize()}/java" else "src/$compilationName/java"
|
||||
|
||||
val javaMainSrcDir = javaSourceRootForCompilation("main")
|
||||
val javaTestSrcDir = javaSourceRootForCompilation("test")
|
||||
|
||||
projectDir.resolve(javaMainSrcDir).apply {
|
||||
mkdirs()
|
||||
// Check that Java can access the dependencies (kotlin-stdlib):
|
||||
resolve("JavaClassInJava.java").writeText(
|
||||
"""
|
||||
package com.example.lib;
|
||||
import kotlin.sequences.Sequence;
|
||||
class JavaClassInJava {
|
||||
Sequence<String> makeSequence() { throw new UnsupportedOperationException(); }
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
// Add a Kotlin source file in the Java source root and check that it is compiled:
|
||||
resolve("KotlinClassInJava.kt").writeText(
|
||||
"""
|
||||
package com.example.lib
|
||||
class KotlinClassInJava
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
projectDir.resolve(javaTestSrcDir).apply {
|
||||
mkdirs()
|
||||
resolve("JavaTest.java").writeText(
|
||||
"""
|
||||
package com.example.lib;
|
||||
import org.junit.*;
|
||||
public class JavaTest {
|
||||
@Test
|
||||
public void testAccessKotlin() {
|
||||
MainKt.expectedFun();
|
||||
MainKt.x();
|
||||
new KotlinClassInJava();
|
||||
new JavaClassInJava();
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
build("clean", "build", "run", "shadowJar") {
|
||||
assertSuccessful()
|
||||
val expectedMainClasses =
|
||||
classesWithoutJava + setOf(
|
||||
"kotlin/jvm6/main/com/example/lib/KotlinClassInJava.class",
|
||||
"java/main/com/example/lib/JavaClassInJava.class",
|
||||
"java/test/com/example/lib/JavaTest.class"
|
||||
)
|
||||
val actualClasses = getFilePathsSet("build/classes")
|
||||
Assert.assertEquals(expectedMainClasses, actualClasses)
|
||||
|
||||
val jvmTestTaskName = if (testJavaSupportInJvmTargets) "jvm6Test" else "test"
|
||||
assertTasksExecuted(":$jvmTestTaskName")
|
||||
assertFileExists("build/reports/tests/$jvmTestTaskName/classes/com.example.lib.JavaTest.html")
|
||||
|
||||
if (testJavaSupportInJvmTargets) {
|
||||
assertNotContains(KotlinJvmWithJavaTargetPreset.DEPRECATION_WARNING)
|
||||
} else {
|
||||
assertContains(KotlinJvmWithJavaTargetPreset.DEPRECATION_WARNING)
|
||||
}
|
||||
""".trimIndent())
|
||||
|
||||
// Add a Kotlin source file in the Java source root and check that it is compiled:
|
||||
resolve("KotlinClassInJava.kt").writeText("""
|
||||
package com.example.lib
|
||||
class KotlinClassInJava
|
||||
""".trimIndent())
|
||||
}
|
||||
assertTasksExecuted(":run")
|
||||
assertContains(">>> Common.kt >>> main()")
|
||||
|
||||
build("clean", "assemble") {
|
||||
assertSuccessful()
|
||||
val expectedClasses =
|
||||
classesWithoutJava +
|
||||
"kotlin/jvm6/main/com/example/lib/KotlinClassInJava.class" +
|
||||
"java/main/com/example/lib/JavaClassInJava.class"
|
||||
val actualClasses = getFilePathsSet("build/classes")
|
||||
Assert.assertEquals(expectedClasses, actualClasses)
|
||||
assertTasksExecuted(":shadowJar")
|
||||
val entries = ZipFile(projectDir.resolve("build/libs/sample-lib-1.0-all.jar")).use { zip ->
|
||||
zip.entries().asSequence().map { it.name }.toSet()
|
||||
}
|
||||
assertTrue { "kotlin/Pair.class" in entries }
|
||||
assertTrue { "com/example/lib/CommonKt.class" in entries }
|
||||
assertTrue { "com/example/lib/MainKt.class" in entries }
|
||||
assertTrue { "com/example/lib/JavaClassInJava.class" in entries }
|
||||
assertTrue { "com/example/lib/KotlinClassInJava.class" in entries }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLibWithTests() = doTestLibWithTests(Project("new-mpp-lib-with-tests", gradleVersion))
|
||||
|
||||
+11
@@ -63,12 +63,23 @@ kotlin {
|
||||
api 'org.jetbrains.kotlin:kotlin-stdlib-common'
|
||||
}
|
||||
}
|
||||
commonTest {
|
||||
dependencies {
|
||||
implementation kotlin("test-common")
|
||||
implementation kotlin("test-annotations-common")
|
||||
}
|
||||
}
|
||||
jvm6Main {
|
||||
dependencies {
|
||||
api 'org.jetbrains.kotlin:kotlin-stdlib'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.23.4'
|
||||
}
|
||||
}
|
||||
jvm6Test {
|
||||
dependencies {
|
||||
implementation kotlin("test-junit")
|
||||
}
|
||||
}
|
||||
nodeJsMain {
|
||||
dependencies {
|
||||
api 'org.jetbrains.kotlin:kotlin-stdlib-js'
|
||||
|
||||
+5
-1
@@ -2,4 +2,8 @@ package com.example.lib
|
||||
|
||||
fun <T> id(t: T): T = t
|
||||
|
||||
expect fun expectedFun(): Unit
|
||||
expect fun expectedFun(): Unit
|
||||
|
||||
fun main() {
|
||||
println(">>> Common.kt >>> main()")
|
||||
}
|
||||
Reference in New Issue
Block a user