스프링부트 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로 변환하는 과정에서 뭔가 문제가 생겼을 것이라 추측하였다.
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가 지정되어 있었다.