Skip to content

Latest commit

 

History

History
372 lines (232 loc) · 14.4 KB

Gradle-Multi-Module-Project-Kotlin-SpringBoot-Upgrade.md

File metadata and controls

372 lines (232 loc) · 14.4 KB

Gradle Multi Module Project Kotlin Spring Boot Upgrade

buildSrc 폴더를 사용하는 Gradle 멀티 모듈 프로젝트에서 코틀린 버전을 업그레이드 해보자.

buildSrc 폴더를 사용하지 않는 경우에는 그냥 build.gradle.kts 파일에서 아래와 같이 kotlin-gradle-plugin의 버전만 명시해주면 된다고 하는데,

// build.gradle.kts

dependencies {
    implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20")
    implementation(kotlin("script-runtime"))
}

buildSrc 폴더를 사용하는 경우에는 그리 간단하지가 않더라능.

buildSrc

// buildSrc/build.gradle.kts

/*
 * This file was generated by the Gradle 'init' task.
 */

plugins {
    // Support convention plugins written in Kotlin. Convention plugins are build scripts in 'src/main' that automatically become available as plugins in the main build.
    `kotlin-dsl`
}

repositories {
    // Use the plugin portal to apply community plugins in convention plugins.
    gradlePluginPortal()
}

extra["kotlinVersion"] = "1.7.20"

dependencies {
    implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${property("kotlinVersion")}")
    implementation(kotlin("script-runtime"))
}

위와 같이 kotlin-gradle-plugin 의 버전만 1.7.20 으로 명시해주면 그냥 될 것 같지만 kotlin-gradle-plugin 의 버전을 명시하면 대략 아래와 같은 에러 중의 하나가 발생하고, 검색해서 이것저것 하다보면 또 아래 에러 중 다른 에러가 나면서 금방 해결은 안 된다.

  • Invalid plugin request [id: ‘org.jetbrains.kotlin.jvm’, version: ‘1.7.20’]. Plugin requests from precompiled scripts must not include a version number. Please remove the version from the offending request and make sure the module containing the requested plugin ‘org.jetbrains.kotlin.jvm’ is an implementation dependency of project ‘:buildSrc’.
  • plugin request for plugin already on the classpath must not include a version
  • java.lang.String org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper.getKotlinPluginVersion()

버전을 명시하면 안 된다거나, 뭔가 kotlin plugin version 을 읽을 수 있는 getKotlinPluginVersion()가 없다는 얘기 같다.

검색하다보니 https://youtrack.jetbrains.com/issue/KT-52790/Gradle-multi-module-NoSuchMethodError-KotlinPluginWrappergetKotlinPluginVersion#focus=Comments-27-6185693.0-0 이런 게 있고 Spring Boot 버전과 플러그인 버전을 올리면 된다는 얘기 같다. 해보자.

Spring Boot 업그레이드

정확하진 않지만 2.7 부터 위에서 말한 문제를 해결해주는 게 아닐까 싶다.
일단 현재 최신 릴리스 버전인 2.7.4 로 시도해본다.

// submodule/build.gradle.kts

plugins {    
    id("org.springframework.boot") version "2.7.4"
    id("io.spring.dependency-management") version "1.0.14.RELEASE"

    kotlin("kapt")  // querydsl 사용하는 경우 필요
    kotlin("plugin.spring") version "1.7.20"
    kotlin("plugin.jpa") version "1.7.20"
    // 기타 생략
}

extra["kotlinVersion"] = "1.7.20"

dependencies {
    implementation("org.jetbrains.kotlin:kotlin-reflect:${property("kotlinVersion")}")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${property("kotlinVersion")}")
    // 기타 생략
}

정말 스프링 부트와 플러그인 버전을 올리니까 된다!!

그럼 스프링을 사용하지 않으면서 buildSrc 폴더를 사용하는 Gradle 멀티 모듈 프로젝트의 코틀린 언어 버전 업그레이드는 어떻게 하나?

몰라. 끗. 이 아니네..

springdoc-openapi

스프링 부트와 플러그인 업그레이드해서 실행해보면 잘 되다가 아래와 같은 스프링 부트 Failure Analyzer 내용이 표시된다.

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2022-10-14 00:36:55.598 ERROR [CreatorCommand,,] 28469 --- [  restartedMain] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

An attempt was made to call a method that does not exist. The attempt was made from the following location:

    org.webjars.WebJarAssetLocator.scanForWebJars(WebJarAssetLocator.java:183)

The following method did not exist:

    'io.github.classgraph.ClassGraph io.github.classgraph.ClassGraph.acceptPaths(java.lang.String[])'

The calling method's class, org.webjars.WebJarAssetLocator, was loaded from the following location:

    jar:file:/Users/user/.gradle/caches/modules-2/files-2.1/org.webjars/webjars-locator-core/0.50/d1ae68f5fea4f8e36e1d9adfd1ac02463c43894a/webjars-locator-core-0.50.jar!/org/webjars/WebJarAssetLocator.class

The called method's class, io.github.classgraph.ClassGraph, is available from the following locations:

    jar:file:/Users/user/.gradle/caches/modules-2/files-2.1/io.github.classgraph/classgraph/4.8.69/6bd8c9033563e162b5c12de12b139724dbf71f48/classgraph-4.8.69.jar!/io/github/classgraph/ClassGraph.class

The called method's class hierarchy was loaded from the following locations:

    io.github.classgraph.ClassGraph: file:/Users/user/.gradle/caches/modules-2/files-2.1/io.github.classgraph/classgraph/4.8.69/6bd8c9033563e162b5c12de12b139724dbf71f48/classgraph-4.8.69.jar


Action:

Correct the classpath of your application so that it contains compatible versions of the classes org.webjars.WebJarAssetLocator and io.github.classgraph.ClassGraph

찾아보니 https://stackoverflow.com/questions/72397763/error-starting-springboot-when-update-version-to-2-7-0-an-attempt-was-made-to-c 이런 자료가 나오는데,
결국 구 버전의 springdoc-openapi 를 사용하고 있으면 springdoc-openapi 내부적으로 사용하는 WebJarAssetLocator, ClassGraph 관련 에러가 난다는 얘기다.

springdoc-openapi 1.5.9에서는 위와 같은 에러가 났었고 아래와 같이 최신 버전 1.6.11 로 변경하니까,

    implementation("org.springdoc:springdoc-openapi-ui:1.6.11")
    implementation("org.springdoc:springdoc-openapi-data-rest:1.6.11")
    implementation("org.springdoc:springdoc-openapi-security:1.6.11")
    implementation("org.springdoc:springdoc-openapi-kotlin:1.6.11")

드디어 성공..

Spring Cloud

하는 줄 알았더니 이번에는 Spring Cloud 관련 에러가..

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2022-10-14 01:01:40.048 ERROR [CreatorCommand,,] 31734 --- [  restartedMain] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Your project setup is incompatible with our requirements due to following reasons:

- Spring Boot [2.7.4] is not compatible with this Spring Cloud release train


Action:

Consider applying the following actions:

- Change Spring Boot version to one of the following versions [2.4.x, 2.5.x] .
You can find the latest Spring Boot versions here [https://spring.io/projects/spring-boot#learn]. 
If you want to learn more about the Spring Cloud Release train compatibility, you can visit this page [https://spring.io/projects/spring-cloud#overview] and check the [Release Trains] section.
If you want to disable this check, just set the property [spring.cloud.compatibility-verifier.enabled=false]


Spring Boot 버전과 Spring Cloud 버전이 안 맞는다는 얘기인 것 같다.

둘 사이의 궁합표는 https://spring.io/projects/spring-cloud 에서 살짝 스크롤 내려보면 'Release train Spring Boot compatibility'에 나와 있다.

Spring Boot 2.7.4 는 Spring Cloud 2021.0.x 와 맞고, 최신인 2021.0.4 를 적용해보자.

// submodule/build.gradle.kts

extra["springCloudVersion"] = "2021.0.4"

dependencyManagement {
    imports {
        mavenBom("org.springframework.cloud:spring-cloud-dependencies:${property("springCloudVersion")}")
    }
}

이번에는 되겠지. 짠!

P6Spy

짠하네..

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2022-10-14 01:13:12.656 ERROR [CreatorCommand,,] 35168 --- [  restartedMain] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

The bean 'p6SpyDataSourceDecorator', defined in class path resource [org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/P6SpyConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [com/github/gavlyukovskiy/boot/jdbc/decorator/p6spy/P6SpyConfiguration.class] and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

이번에는 실행되는 쿼리를 편하게 볼 수 있는 P6Spy와 Spring Cloud Sleuth가 충돌이 있는 것 같다.

P6SpyConfiguration 클래스가 com/github/gavlyukovskiy/boot/jdbc/decorator/p6spy/P6SpyConfiguration.class 에도 있고,
com/github/gavlyukovskiy/cloud/sleuth 에도 있고, org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/P6SpyConfiguration.class 에도 있다.

https://github.com/gavlyukovskiy/spring-boot-data-source-decorator#spring-cloud-sleuth-deprecated 이걸 보고 아래와 같이 조치한다.

  1. properties(yml) 파일에서 decorator.datasource.spring.sleuth.jdbc.로 일괄 변경
  2. build.gradle.kts 파일에서 implementation("com.github.gavlyukovskiy:p6spy-spring-boot-starter")implementation("p6spy:p6spy")로 일괄 변경.. 하면 p6spy 를 못 찾는다고 하니 implementation("p6spy:p6spy:3.9.1")로 일괄 변경

QueryDsl

Spring Boot 2.7 에서는 QueryDsl 도 5.0.0 을 사용해야 하는 모양이다.

아래와 같이 지정해주면 된다.

// submodule/build.gradle.kts

extra["queryDslVersion"] = "5.0.0"

dependencies {
    implementation("com.querydsl:querydsl-jpa:${property("queryDslVersion")}")
    kapt("com.querydsl:querydsl-apt:${property("queryDslVersion")}:jpa")

    annotationProcessor("jakarta.persistence:jakarta.persistence-api")
    annotationProcessor("jakarta.annotation:jakarta.annotation-api")
}

JUnit Jupiter

테스트를 돌려보니 이번엔 아래와 같은 에러가.. 그것도 IDE 로그에는 상세 정보 안 나오고 테스트 결과 html을 보라는 로그만 나온다.
html 을 보면 다음과 같다.

Imgur

TestEngine with ID 'junit-jupiter' failed to discover tests 요런 게 나오는 걸로 보니 junit-jupiter 관련 의존관계 문제일 거라 보고 설치된 버전을 보니 아래와 같이 junit-jupiter-api 만 다른 애들과 달리 5.7.1 이다.

어딘가 수동으로 버전 명시한 게 있는 것 같아 찾아보니 아래와 같이 gradle init에 의해 자동 생성된 파일에 버전이 뙇..

// ***.kotlin-common-conventions.gradle.kts

/*
 * This file was generated by the Gradle 'init' task.
 */

plugins {
    // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin.
    id("org.jetbrains.kotlin.jvm")
}

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

dependencies {
    constraints {
        // Define dependency versions as constraints
        implementation("org.apache.commons:commons-text:1.9")

        implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    }

    // Align versions of all Kotlin components
    implementation(platform("org.jetbrains.kotlin:kotlin-bom"))

    // Use the Kotlin JDK 8 standard library.
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")

    // Align versions of all Kotlin components
    implementation(platform("org.jetbrains.kotlin:kotlin-bom"))

    // Use JUnit Jupiter API for testing.
    testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.1")  // 여기!!

    // Use JUnit Jupiter Engine for testing.
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}

tasks.test {
    // Use junit platform for unit tests.
    useJUnitPlatform()
}

testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.1")에서 버전 번호를 삭제하면 드디어..

로컬 성공

이제 드디어!!

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.7.4)

2022-10-14 01:45:52.562  INFO [CreatorCommand,,] 39888 --- [  restartedMain] m.z.s.w.c.c.CreatorCommandApplicationKt  : Starting CreatorCommandApplicationKt using Java 14.0.2 on abcde
2022-10-14 01:45:52.564 DEBUG [CreatorCommand,,] 39888 --- [  restartedMain] m.z.s.w.c.c.CreatorCommandApplicationKt  : Running with Spring Boot v2.7.4, Spring v5.3.23

Jenkins, JaCoCo

드디어 로컬에서는 성공!

그런데 Jenkins를 돌려보니 에러

// Jenkins Job Console Log

java.lang.IllegalStateException: Unexpected SMAP line: *S KotlinDebug
    at org.jacoco.core.internal.analysis.filter.KotlinInlineFilter.getFirstGeneratedLineNumber(KotlinInlineFilter.java:98)
    at org.jacoco.core.internal.analysis.filter.KotlinInlineFilter.filter(KotlinInlineFilter.java:44)
    at org.jacoco.core.internal.analysis.filter.Filters.filter(Filters.java:59)
    at org.jacoco.core.internal.analysis.ClassAnalyzer.addMethodCoverage(ClassAnalyzer.java:119)
    at org.jacoco.core.internal.analysis.ClassAnalyzer.access$100(ClassAnalyzer.java:33)
    at org.jacoco.core.internal.analysis.ClassAnalyzer$1.accept(ClassAnalyzer.java:108)
    at org.jacoco.core.internal.flow.ClassProbesAdapter$2.visitEnd(ClassProbesAdapter.java:91)
    at org.objectweb.asm.ClassReader.readMethod(ClassReader.java:1492)
    at org.objectweb.asm.ClassReader.accept(ClassReader.java:718)
    at org.objectweb.asm.ClassReader.accept(ClassReader.java:401)
    at org.jacoco.core.analysis.Analyzer.analyzeClass(Analyzer.java:116)
    at org.jacoco.core.analysis.Analyzer.analyzeClass(Analyzer.java:132)

검색 해 보니, https://blog.leocat.kr/notes/2021/06/13/jacoco-Unexpected-SMAP-line-S-KotlinDebug-kotlin-1.5 요런 게 나오는데, Jenkins JaCoCo 플러그인 버전을 3.2.0 이상으로 올려야 한단다. 그러려면 Jenkins도 2.277.1 이상으로 올려야 한단다.

그래서 그냥 Job 설정에서 JaCoCo 플러그인 실행 부분을 그냥 삭제했다. 나중에 Jenkins 업그레이드 하게 되면 그때나 적용해보기로..