본문 바로가기

백엔드 개발/코틀린(Kotlin)

Querydsl을 사용하는 자바(JAVA) Spring Framework 프로젝트에 코틀린(Kotlin) 설정

반응형

1. QueryDSL이란?

Spring Framework에서 JPA, QueryDsl 조합을 애용하고 있다.

특히, QueryDsl을 사용하면 SQL, JPQL을 type safe하게 작성할 수 있다.

type safe하게 작성할 수 있다는 것은 IDE의 지원을 받아서 쉽고 안전하게 Query를 작성할 수 있다는 의미이다.

그리고 Spring Data JPA를 사용하면 다이나믹 쿼리를 사용할 수 없어서 코드가 장황해지고 중복되는데.

QueryDsl는 다이나믹 쿼리를 작성가능해서 반복되는 코드수를 줄일 수 있다.

 

2. 자바(Java)를 사용하는 Spring data jpa project에서 QueryDsl 설정

QueryDsl을 사용하려면 컴파일(Compile)시에 QClass를 생성하기 위한 설정을 해야하는데.

gradle 5.0 이상을 사용하는 Spring Boot Data Jpa 프로젝트에서 QueryDsl 설정하는 방법은 링크에서 잘 설명되어있다.

gradle 5.0 이상에서 설정하면 이전보다 간편해서 gradle 5.0 이상을 사용해서 설정하기를 추천한다.

 

3. QueryDsl을 사용하는 자바 프로젝트에 코틀린을 도입하는 방법

위 설정은 자바만을 사용하는 과정이다.

QueryDsl을 사용하는 자바 프로젝트에 코틀린을 도입하는 방법을 소개하겠다.

우선 코틀린을 자바 프로젝트에 설정하는 방법은 아래 두 링크를 참고하면 된다.

 

Spring Boot 2.0, Gradle 기반 프로젝트에 Java, Kotlin 동시에 적용하기

코틀린 공식 사이트의 그레들을 사용하는 설정에 대한 문서

 

Tip.

첫번째 링크의 build.gradle에 plugin을 설정하는 부분은 아래와 같다.
buildscript {
    ext {
        kotlinVersion = '1.3.41'
        springBootVersion = '2.2.5.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
        classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
        classpath("org.jetbrains.kotlin:kotlin-noarg:${kotlinVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
............ 중략 .....

 

위 부분은 아래와 같이 작성 가능하다. 
필자가 두번째 링크를 보고 임의로 변경해본 것이다.
두가지 방식이 있다는 것만 알아두었으면 좋겠다.

 

plugins {
	id 'org.springframework.boot' version '2.2.5.RELEASE'
	id 'io.spring.dependency-management' version '1.0.9.RELEASE'
	id 'java'
    id 'eclipse'
	id 'org.jetbrains.kotlin.jvm' version '1.3.72'
	id 'org.jetbrains.kotlin.plugin.spring' version "1.3.72"
	id 'org.jetbrains.kotlin.plugin.jpa' version "1.3.72"
	id 'org.jetbrains.kotlin.plugin.allopen' version "1.3.72"
	id 'org.jetbrains.kotlin.kapt' version "1.3.72"
}

repositories {
	mavenCentral()
}

 

'org.jetbrains.kotlin.plugin.jpa' 플러그인은 코틀린으로 작성된 JPA Entity에 파라미터없는 기본 생성자를 자동으로 만들어준다.
'org.jetbrains.kotlin.plugin.allopen'는 코틀린으로 작성된 JPA Entity를 open 시켜준다. 
(코틀린은 클래스를 기본적으로 상속 불가능하게 설정한다. 그래서 open이라는 키워드를 붙여줘야 상속가능하다.)

 

 

처음부터 KotlinDsl로 build.gradle를 변경하는 것보다는 기존 groovy script를 변경하는 것을 추천한다.

만약, 신규 프로젝트라면 spring Initializr로 생성하는 코틀린 프로젝트는 KotlinDsl로 build.gradle가 구성되어있다.


4. 빌드 실패의 원인

 

위의 과정을 도입하는 것이 어렵지 않다.

만약 인텔리J를 사용한다면 프로젝트 실행도 문제가 없을것이다.

그런데 compileQuerydsl 과정 중에 

[코틀린 클래스명].class cannot find symbol 이라는 에러 로그가 콘솔창에 나타나면서 gradle build가 실패한다.

 

필자의 경우 JPA 엔티티를 코틀린으로 작성하지는 않았었다.
위에 에러로 로깅된 코틀린 클래스는 자바로 작성된 JpaRepository를 멤버로 가지고 있는 Service 클래스였다.
CompileQueryDsl task 실행하면서 QClass를 생성하는 중에 코틀린 클래스를 인식하지 못했다.
 
원인을 추정해보면 annotation processing 과정이 kotlin 컴파일보다 늦기 때문이라고 생각한다.
java와 kotlin을 사용하는 프로젝트에서 컴파일은 아래와 같은 순서로 이루어 진다.

1. Kotlin 컴파일 (이때, Kotlin 코드가 참조하는 java 코드도 같이 로딩된다.)
2. Java 컴파일 (Kotlin이 컴파일한 .class 파일의 경로를 클래스 패스에 추가하면서 컴파일)

우리가 사용하는 QueryDSL의 QClass들은 Annotation Processing이 일어나는 2 번째 과정에서 생성된다.
이 때 Java 컴파일러가 Kotlin 코드를 인지하지 못한다고 한다.
코틀린으로 작성된 JPA 엔티티 클래스 뿐만이 아니라 JPA와 관련있는 코틀린으로 작성된 객체들은 인식 못하는 것으로 보인다. 

더 자세한 내용은 아래 링크 참고
Kotlin 도입 과정에서 만난 문제와 해결 방법

컴파일 순서 때문에 기존에 annotationProcessor를 사용하는 라이브러리는 kapt로 다 처리하도록 해야 오류를 막을 수 있다.

필자가 사용하는 MapStruct라는 라이브러리도 코틀린을 도입하는 과정에서 kapt로 처리하도록 변경하니 아무 문제도 없었다.

5. 빌드 실패를 해결하는 방법

이 오류를 마주하고 헤매다가 해결책은 의외로 간단하다는 것을 알게되었다.

일단 기존의 queryDsl의 설정은 모두 제거하고 아래 설정만 추가해주면 된다.

그러면 빌드나 실행 모두 정상적으로 되는 것을 확인할 수 있다.

 

plugins {
// ...
    kotlin("kapt") version "1.3.61"
}
dependencies {
// ...
    implementation("com.querydsl:querydsl-jpa:4.2.2")
    kapt("com.querydsl:querydsl-apt:4.2.2:jpa")
}

기존에는 compileQueryDsl task로 QClass를 생성했지만 compileKotlin으로 QClass를 생성할 수 있다.

 

 

아래 링크에는 QueryDSL을 코틀린 프로젝트에 적용하는 여러 설정들이 나와있다.

 

https://github.com/querydsl/querydsl/issues/1828

반응형