spring-gradle-plugins / dependency-management-plugin

A Gradle plugin that provides Maven-like dependency management functionality
690 stars 88 forks source link

Imports spring-boot-dependencies impacts Kotlin version in kotlinCompilerClasspath #235

Closed mcoolive closed 5 years ago

mcoolive commented 5 years ago

Hi,

I am facing to a strange issue. After I migrate my project from Kotlin 1.2.x to Kotlin 1.3.10, I get the following compilation error when I include spring-boot-dependencies BOM

The root cause was thrown at: IntrinsicArrayConstructors.kt:32 Caused by: java.lang.NoSuchMethodError: kotlin.io.ByteStreamsKt.readBytes(Ljava/io/InputStream;)[B

After investigation, my build uses incompatible versions of Kotlin. I solved some incompatibilities by specifying the version for all kotlin-stdlib-* in my project's dependencies. But the above issue remains at compile time. Below an extract of the dependencies of my project:

kotlinCompilerClasspath --- org.jetbrains.kotlin:kotlin-compiler-embeddable:1.3.10 +--- org.jetbrains.kotlin:kotlin-stdlib:1.3.10 -> 1.2.51 | +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.2.51 | --- org.jetbrains:annotations:13.0 +--- org.jetbrains.kotlin:kotlin-script-runtime:1.3.10 --- org.jetbrains.kotlin:kotlin-reflect:1.3.10 -> 1.2.51 --- org.jetbrains.kotlin:kotlin-stdlib:1.2.51 (*)

So kotlin-stdlib and kotlin-stdlib-common are downgraded in kotlinCompilerClasspath. But their version are correct in other class paths (including compileClasspath). That's why I observe the first issue only with a piece of code that create an Array (the constructor is inlined and depends on Kotlin API 1.3...)

The version 1.2.51 comes from kotlin.version which is defined by Spring Boot BOM. I don't understand why it affects only the Kotlin compile classpath, I suspect a naming collision with kotlin-jvm plugin.

I am using:

To reproduce, execute ./gradlew dependencies with the following build.gradle.kts file

group = "fr.mcoolive"
version = "1.0.0-SNAPSHOT"
plugins {
    kotlin("jvm") version "1.3.10"
    id("io.spring.dependency-management") version "1.0.6.RELEASE"
}
dependencyManagement {
    imports {
        mavenBom("org.springframework.boot:spring-boot-dependencies:2.0.6.RELEASE")
    }
}
repositories {
    jcenter()
}
dependencies {
    compile(kotlin("stdlib-jdk8"))
    compile(kotlin("stdlib-jdk7"))
    compile(kotlin("stdlib"))
    compile(kotlin("stdlib-common"))
}
wilkinsona commented 5 years ago

This is working as designed. spring-boot-dependencies manages the version of several Kotlin modules giving them a version of 1.2.51. There are some new modules in Kotlin 1.3.10 that aren't managed so they retain their default version. As a result, you are left with a mixture of versions.

They can be aligned by setting the kotlin.version property to 1.3.10. In Groovy that could be done with the following:

ext['kotlin.version'] = '1.3.10'
mcoolive commented 5 years ago

Thank you for your prompt answer. It works! The equivalent with Kotlin DSL is

extra["kotlin.version"] = "1.3.10" // ext or extra, both works for me

It does not explain why only kotlinCompilerClasspath was affected. As far I understand kotlin-gradle-plugin defines automatically ext.kotlin_version (an underscore, not a dot) which should be used by kotlin-dsl to set up ALL class paths. I have to dig more, but the issue is clearly not in spring-boot-dependencies.

By the way, it is painful to have to repeat the Kotlin version. Maybe relying on Gradle's improved pom can be simpler in my case. The issue "Relationship between this plugin and Gradle's improved pom support" helps me to understand what happens.

Thank you for the guidance.

wilkinsona commented 5 years ago

which should be used by kotlin-dsl to set up ALL class paths. I have to dig more, but the issue is clearly not in spring-boot-dependencies.

It may well be used for all class paths, but that would not necessarily prevent the dependency management plugin's resolution strategy from overriding the version based on what is specified in spring-boot-dependencies.

By the way, it is painful to have to repeat the Kotlin version.

Agreed. That's why Spring Boot's Gradle plugin (which you're not using) automatically aligns the two so the repetition is not necessary.