회사에서 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
블록에서 jpa
을 true
로 하는 경우, QClass
를 자동으로 생성하게 된다.
이때, com.querydsl.apt.jpa.JPAAnnotationProcessor
가 추가되면서 프로젝트에 사용된다.
그리고 querydslSourceDir
에 정의된 디렉토리에 QClass를 생성하게 되는데
나는 $BuildDir/generated/querydsl
으로 지정하였다.
Symbol
에러가 발생했다는 뜻은 컴파일은 잘되었을 테고, QClass를 생성하려면 AnnotationProcessor가 작동해서 생성했을 텐데
아마 querydsl의 AnnotationProcessor가 QClass를 생성하는 과정에서 어떠한 문제가 있지 않았을까 의심해보았다.
3. 그럼 Annotation Processor 설정에 문제가??
인텔리제이에서 어노테이션 프로세스 설정 관련 문제는 대부분 아래 두가지였다.
Enable annotation processing
을 체크하지 않은 경우Store generated sources relative to
가Module 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
그룹을 삭제하였다)
출처