새소식

토토로 일지

스프링부트 JPA QueryDSL cannot find symbol Error를 해결해보자.

  • -

TIL : 스프링부트 JPA QueryDSL cannot find symbol Error를 해결해보자.

 

    Spring Boot 프로젝트에서 Spring Data JPA를 사용할 때 cannot find symbol Error를 만났다. JPA에서 쿼리를 작성하는 방법은 쿼리메소드, @Query, QueryDSL이 있는데, 확장성 있는 쿼리를 작성할 때는 QueryDSL이 필수라고 한다.

 

문제 발생


 

원래는 빌드 설정을 통해 자동으로 Q도메인으로 변환되었어야 하는데..

 

cannot find symbol 오류

 

 

해당 에러를 읽어보면 "컴파일 단계에서 컴파일러가 symbol을 이해하지 못한다." 고 적혀있다.

 

추측


💡 symbol은 보통 우리가 선언한 변수 등을 가르킨다.

 

    예를 들어 아래와 같은 코드가 있을 때, message라는 변수의 타입을 지정하지 않으면 컴파일 단계에서 Can not find Symbol 에러가 발생한다.

class Main {

    public static void main(String[] args){
        message = "Can not find Symbol!";
    }
}

 

 

    에러 메세지에서 보다시피 symbol: variable message를 가리키고 있다.  그런 관점에서 봤을 때 해당 에러는 컴파일 당시에 해당 QClass로 변환하는 과정에서 뭔가 문제가 생겼을 것이라 추측하였다.

 

원인


💡 Lombok 충돌, 버전 오류, 빌드 설정 오류, 프로젝트 설정 오류

 

해당 추측을 바탕으로 원인을 하나씩 살펴보기로 했다.

 

해결 시도 1


Gradle 설정을 확인해봤다.

plugins {
    id 'com.ewerk.gradle.plugins.querydsl' version '1.0.10'
}

dependencies {
    implementation 'com.querydsl:querydsl-jpa'
}

def querydslDir = '$buildDir/generated/querydsl'

querydsl {
    jpa = true
    querydslSourceDir = querydslDir
}

sourceSets {
    main.java.srcDir querydslDir
}

configurations {
    querydsl.extendsFrom compileClasspath
}

compileQuerydsl {
    options.annotationProcessorPath = configurations.querydsl
}

 

크게 이상이 있지는 않았다.

 

해결 시도 2


컴파일 과정에서 QueryDSL 오류가 발생하는 경우가 종종 있다고 한다.

 

Gradle - querydsl - clean And init

 

초기화를 해보았으나 달라지지 않았다.

 

해결 시도 3


QueryDSL은 컴파일 단계에서 generated라는 폴더에 QClass를 생성시킨다.

def querydslDir = "$buildDir/generated/querydsl"    // QClass 생성 위치

querydsl {
    library = "com.querydsl:querydsl-apt"              
    jpa = true
    querydslSourcesDir = querydslDir
}

    QueryDSL 설정을 보면, querydsl 블록에서 jpa을 true로 하는 경우, QClass를 자동으로 생성하게 된다.

 

    com.querydsl.apt.jpa.JPAAnnotationProcessor가 추가되면서 프로젝트에 사용된다. 그리고 querydslSourceDir에 정의된 디렉토리에 QClass를 생성하게 되는데, 나는 $BuildDir/generated/querydsl으로 지정하였다.

    Symbol에러가 발생했다는 뜻은 컴파일은 잘되었을 테고, QClass를 생성하려면 AnnotationProcessor가 작동해서 생성했을 텐데, 아마 querydsl의 AnnotationProcessor가 QClass를 생성하는 과정에서 어떠한 문제가 있지 않았을까 의심해보았다.


Annotation Processor 설정을 확인해보자.


 

 

인텔리제이에서 어노테이션 프로세스 설정 관련 문제는 대부분 아래 두가지였다.

💡 Enable annotation processing을 체크하지 않은 경우
💡 Store generated sources relative to가 Module output directory에 체크를 하지 않은 경우

하나는 어노테이션 프로세싱을 못하게 된 상태이고, 다른 하나는 path가 제대로 설정이 되지 않은 경우였다.

    나의 경우는 둘 다 제대로 설정된 상태였음에도 불구하고 제대로 동작하지 않았고, Intellij의 Annotation Processing 문서를 읽던 도중 아래의 문구를 발견하였다.

 

 

    인텔리제이의 Annotation Processor의 기본동작은 Annotation Processor가 classpath에 있으면 가져와서 사용하고, 외부에 있다면 어노테이션 프로세서 JAR를 직접 path에 넣어서 사용한다.

    인텔리제이의 좋은 점은 gradle과 같은 build script를 사용할 때 알아서 어노테이션 프로세싱을 해주고 적절한 path 또한 세팅해준다는 점이다.

그렇다면 어디에서 어떻게 세팅을 할 것인가인데 바로 아래 부분에서 찾을 수 있었다.

 

 

인텔리제이에서는 profile이라고 하는 어노테이션 프로세서에 필요한 설정 옵션 그룹을 지정하여 사용한다.
기본적으로 프로젝트의 모든 모듈은 default profile을 사용하여 설정을 하게 된다.
같은 모듈이더라도 그룹이 다르게 되면 다른 어노테이션 프로세스 설정을 사용하게 된다.

 

    이 부분을 보고 설정을 살펴보니 default 그룹 이외에 Gradle Imported라는 그룹이 따로 설정되어 있었다. 그 아래 모듈이 하나가 있었는데 에러를 발생하는 클래스를 가지는 모듈이었다.

 

 

정확하게는 Gradle Imported처럼 profile이 다르더라도 내부 설정이 같으면 정상적으로 잘 돌아간다.

 

나의 경우는 Gradle Imported를 사용한 동시에 특정 Processor path가 지정되어 있었다.

 

 

C:\Users\bgpark\.gradle\caches\modules-2\files-2.1\
org.projectlombok\lombok\1.18.10\625fc0055674dff70dbc76efa36d0f2c89b04a24\lombok-1.18.10.jar

 

    자세히 살펴보면 gradle.cache의 경로를 사용하고 있는데 분명 예전 프로젝트에서 사용했었던 캐시를 어떤 이유에서 인지 인텔리제이가 인식을 하고 있던 것으로 보인다.

    기본적으로는 Obtain processors from project classpath로 지정하여 프로젝트의 class path를 자동적으로 사용하도록 설정하여야 한다.

 

해결 방법


왼쪽 상단의 오른쪽 화살표를 눌러서 Gradle Imported 아래 모듈을 Default profile로 옮기면서 오류를 해결할 수 있었다. Default profile로 옮김으로써 Default 그룹의 옵션을 강제로 사용하게 만들었다.

 


결과


 

 

    어노테이션 프로세서의 설정 그룹인 profile을 프로젝트가 사용하는 Default 그룹으로 옮기면서 컴파일이 잘 수행하는 것을 확인할 수 있었다.

 

Contents

가져가줭

공감 눌러줭