본문 바로가기
Programming/Spring

[QueryDsl] Can not find symbol 에러 해결

by peter paak 2021. 3. 15.
728x90

회사에서 QueryDSL을 사용하고 있는데 몇일전부터 위의 Can not find symbol에러가 나왔다.
언제쯤부터인지는 모르겠으나 새로 빌드를 할 때 위의 에러가 나왔는데 한번 살펴보려고 한다

1. Can not find symbol은 무슨 뜻이지?

먼저 Can not find symbol에서 symbol의 의미를 알아야 문제를 해결할 수 있을 것 같았다.

Can not 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로 제대로 컴파일 당시에 뭔가 문제가 생겼을 것이라 추측하였다

2. 그럼 generated가 의심스럽다

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

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

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

QueryDSL 설정을 보면,
querydsl 블록에서 jpatrue로 하는 경우, QClass를 자동으로 생성하게 된다.
이때, com.querydsl.apt.jpa.JPAAnnotationProcessor가 추가되면서 프로젝트에 사용된다.
그리고 querydslSourceDir에 정의된 디렉토리에 QClass를 생성하게 되는데
나는 $BuildDir/generated/querydsl으로 지정하였다.

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

3. 그럼 Annotation Processor 설정에 문제가??

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

  1. Enable annotation processing을 체크하지 않은 경우
  2. Store generated sources relative toModule output directory에 체크를 하지 않은 경우

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

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

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

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

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

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

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

정확하게는 Gradle Imported처럼 profile이 다르더라도 내부 설정이 같으면 정상적으로 잘 돌아간다.
(왜냐하면 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 그룹으로 옮기면서 컴파일이 잘 수행하는 것을 확인할 수 있었다. (그래도 혹시 모르니 기존의 Gradle Imported 그룹을 삭제하였다)

출처

728x90