인프런 커뮤니티 질문&답변

백엔드 주니어 개발자님의 프로필 이미지
백엔드 주니어 개발자

작성한 질문수

실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)

querydsl을 사용할 때 java의 Q클래스와 kotlin의 Q클래스 함께사용 가능한가요??

작성

·

720

0

기존에 진행 중이던 프로젝트에서 신규로 개발할 기능들은 kotlin으로 개발하려합니다. 강사님 강의에서 나온 프로젝트의 build.gradle 파일을 참고해서 설정을 하니 java의 Q클래스와 kotlin의 Q클래스가 둘다 생겨버려서 중복이라는 에러가 발생하더군요.... 혹시 java,kotlin 2개를 동시에 Q클래스를 사용할 수 있는 방법은 없을까요??

아니면 java의 Q클래스만 생성해서 kotlin에서 java에서 생성한 Q클래스를 사용하면 될까요??그런데 이 방법으로 시도해보려니 설정이 꼬여서 그런지 자꾸 Q클래스는 생성읻되었는데 경로를 못찾는다고 에러가 발생하더라고요ㅠㅠ 좋은 방법있으면 알려주시면 감사하겠습니다.

 

plugins {
    id 'org.springframework.boot' version '2.2.2.RELEASE'
    id 'io.spring.dependency-management' version '1.0.8.RELEASE'
    id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
    id 'java'
    id 'org.jetbrains.kotlin.jvm' version '1.6.21'
    id 'org.jetbrains.kotlin.plugin.jpa' version '1.6.21'
    id 'org.jetbrains.kotlin.plugin.spring' version '1.6.21'
    id 'org.jetbrains.kotlin.kapt' version '1.6.21'
}

group = 'com.maturi'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '8'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
    developmentOnly
    runtimeClasspath {
        extendsFrom developmentOnly
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    developmentOnly("org.springframework.boot:spring-boot-devtools")
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
    runtimeOnly 'org.mariadb.jdbc:mariadb-java-client:2.7.0'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    implementation 'org.modelmapper:modelmapper:2.4.2'
    testCompileOnly 'org.projectlombok:lombok'
    testAnnotationProcessor 'org.projectlombok:lombok'
    implementation 'org.springframework.boot:spring-boot-starter-mail'
    implementation 'com.querydsl:querydsl-jpa'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
    implementation group: 'org.javassist', name: 'javassist', version: '3.15.0-GA'
    implementation group: 'com.google.firebase', name: 'firebase-admin', version: '8.1.0'
    implementation 'org.springframework.social:spring-social-facebook:2.0.3.RELEASE'
    implementation 'org.apache.httpcomponents:httpclient:4.5.2'
    implementation 'com.googlecode.json-simple:json-simple:1.1.1'
    kapt("com.querydsl:querydsl-apt:5.0.0:jpa")
    kapt("org.springframework.boot:spring-boot-configuration-processor")
}

test {
    exclude { '/**/*' }
    useJUnitPlatform()
}

compileKotlin {
    kotlinOptions {
        jvmTarget = "8"
    }
}

compileTestKotlin {
    kotlinOptions {
        jvmTarget = "8"
    }
}

def querydslDir = "$buildDir/generated/querydsl"
querydsl {
    jpa = true
    querydslSourcesDir = querydslDir
}

sourceSets {
    main.java.srcDir querydslDir
}

configurations {
    querydsl.extendsFrom compileClasspath
}

compileQuerydsl {
    options.annotationProcessorPath = configurations.querydsl
}

clean {
    delete file('src/main/generated')
}

답변 1

0

최태현님의 프로필 이미지
최태현
지식공유자

안녕하세요!! 질문 주셔서 감사합니다! 😊

 

결론부터 말씀드리면 저도 Querydsl과 java + kotlin 을 동시에 조합해본 적은 없어서 확신에 가득찬 말씀을 드리기는 어려울 것 같습니다! 🥺

 

설정을 하니 java의 Q클래스와 kotlin의 Q클래스가 둘다 생겨버려서 중복이라는 에러가 발생하더군요.... 혹시 java,kotlin 2개를 동시에 Q클래스를 사용할 수 있는 방법은 없을까요??

다만, 제가 추측하기로는 동일한 Entity 객체가 동시에 java와 kotlin으로 있는 것이 아니면, QClass가 2개 생기지는 않을 것 같아요! 혹시라도 두 개가 생겼다면 이전에 생겼던 QClass가 정상적으로 지워지지 않은게 아닐까.. 싶습니다!

 

아니면 java의 Q클래스만 생성해서 kotlin에서 java에서 생성한 Q클래스를 사용하면 될까요??그런데 이 방법으로 시도해보려니 설정이 꼬여서 그런지 자꾸 Q클래스는 생성읻되었는데 경로를 못찾는다고 에러가 발생하더라고요ㅠㅠ

그리고 이 방법도 충분히 사용 가능할 것으로 생각됩니다! 결국 QClass 를 kotlin에서 사용하건 java에서 사용하건 해당 Class를 import 해서 쓰기만 하면 되거든요!

이때 경로를 찾지 못하는 문제는 멀티 모듈을 사용하신다면 모듈 간의 의존성 문제일 수도 있고, 아니면 IntelliJ에서 특정 폴더에 대한 project source set 인지를 못해서 그럴 수도 있을 것 같습니다.

 

혹시 프로젝트 공유가 가능하시다면 확인 한 번 해보도록 하겠습니다.

github도 좋고, choi-0202@naver.com 메일도 좋습니다. 중요한 부분은 모두 정리하시고 java class + kotlin class 안되는 부분만 남겨주셔도 되어요!

감사합니다! 🙏

깃헙계정 입니다! 감사합니다ㅎㅎ
https://github.com/onetaek/linePig

 

코틀린 파일은 하나도 없고 java 파일만 있는 상태이고, build.gradle 설정만 바꾸었는데 Q클래스가 2개 생성되고있습니다ㅠㅠㅠ 아마 build.gradle의 Q클래스 경로 설정문제인거 같은데 도와주시면 감사하겠습니다ㅠㅠㅠ

아래와 같이 build.gradle에 주석을 달아서 코틀린 도입하며 추가한 build.gradle 코드를 표시하였습니다!!

//--------코틀린 도입을 위한 추가 코드 start-------------

//--------코틀린 도입을 위한 추가 코드 end-------------


image

plugins {
    id 'org.springframework.boot' version '2.2.2.RELEASE'
    id 'io.spring.dependency-management' version '1.0.8.RELEASE'
    id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
    id 'java'

    //--------코틀린 도입을 위한 추가 코드 start-------------
    id 'org.jetbrains.kotlin.jvm' version '1.6.21'
    id 'org.jetbrains.kotlin.plugin.jpa' version '1.6.21'
    id 'org.jetbrains.kotlin.plugin.spring' version '1.6.21'
    id 'org.jetbrains.kotlin.kapt' version '1.6.21'
    //--------코틀린 도입을 위한 추가 코드 end-------------
}

group = 'com.maturi'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '8'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
    developmentOnly
    runtimeClasspath {
        extendsFrom developmentOnly
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    developmentOnly("org.springframework.boot:spring-boot-devtools")
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
    runtimeOnly 'org.mariadb.jdbc:mariadb-java-client:2.7.0'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    implementation 'org.modelmapper:modelmapper:2.4.2'
    testCompileOnly 'org.projectlombok:lombok'
    testAnnotationProcessor 'org.projectlombok:lombok'
    implementation 'org.springframework.boot:spring-boot-starter-mail'
    implementation 'com.querydsl:querydsl-jpa'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
    implementation group: 'org.javassist', name: 'javassist', version: '3.15.0-GA'
    implementation group: 'com.google.firebase', name: 'firebase-admin', version: '8.1.0'
    implementation 'org.springframework.social:spring-social-facebook:2.0.3.RELEASE'
    implementation 'org.apache.httpcomponents:httpclient:4.5.2'
    implementation 'com.googlecode.json-simple:json-simple:1.1.1'

    //--------코틀린 도입을 위한 추가 코드 start-------------
    kapt("com.querydsl:querydsl-apt:5.0.0:jpa")
    kapt("org.springframework.boot:spring-boot-configuration-processor")
    //--------코틀린 도입을 위한 추가 코드 end-------------
}

test {
    exclude { '/**/*' }
    useJUnitPlatform()
}

//--------코틀린 도입을 위한 추가 코드 start-------------
compileKotlin {
    kotlinOptions {
        jvmTarget = "8"
    }
}

compileTestKotlin {
    kotlinOptions {
        jvmTarget = "8"
    }
}
//--------코틀린 도입을 위한 추가 코드 end-------------

def querydslDir = "$buildDir/generated/querydsl"
querydsl {
    jpa = true
    querydslSourcesDir = querydslDir
}

sourceSets {
    main.java.srcDir querydslDir
}

configurations {
    querydsl.extendsFrom compileClasspath
}

compileQuerydsl {
    options.annotationProcessorPath = configurations.querydsl
}

clean {
    delete file('src/main/generated')
}
최태현님의 프로필 이미지
최태현
지식공유자

안녕하세요, 백엔드 개발자 취준생님! 😊 보내주신 github 코드로 이것저것 살펴보며 대략적으로 문제를 해결해서 몇 가지 말씀 드려 보도록 하겠습니다.

 

[1. 왜 QClass가 2개 생겼는가]

결론부터 말씀드리면, QClass가 2개씩 생기던게 맞습니다. 그렇다면 왜 2개씩 생겼는가?

그것은 중첩된 Querydsl 설정 때문입니다.

설정해두셨던 build.gradle 을 살펴보면

  • querydsl에 대해 플러그인이 설정되어 있고

  • 동시에 querydsl을 직접 import 해서 어노테이션 프로세싱을 해주고 있습니다.

전자는 원래 있던 설정이고, 후자는 Kotlin을 추가해 보시려고 넣으신 설정일 거에요!

 

문제는 이제 이 각각의 설정이 별도로 적용되어 있다 보니 Querydsl QClass가 2개씩 생기게 되었습니다.

 

[2. 그렇다면 어떻게 해결해야 하는가]

중첩된 Querydsl 설정 중 하나만 사용하시면 됩니다! 전자의 설정을 그대로 사용하시더라도, Kotlin 으로 작성된 Repository에서 QClass를 가져와 사용하는 것은 전혀 문제가 없을거에요!

 

다만, 만약 후자의 설정을 사용하신다면, 현재 스프링 부트 버전이 2.x.x 버전이고 스프링 부트 2.6.x 쯔음 부터는 Querydsl 5.0.0 버전을 사용하고 있다보니 스프링 부트 버전 업그레이드가 필요할 수 있습니다.

관련 포스트

 

답변이 도움이 되었으면 좋겠습니다. 감사합니다. 🙏 🙇

백엔드 주니어 개발자님의 프로필 이미지
백엔드 주니어 개발자

작성한 질문수

질문하기