본문 바로가기

좌충우돌 개발기!/DB 설정

[Spring Boot] (4) 스프링부트 3에서의 QueryDSL 설정 변경

기존 스프링부트 2.x에서 QueryDSL 설정은 아래와 같다.

 

build.gradle

// queryDSL version 정보
buildscript {
    ext {
       queryDslVersion = "5.0.0"
    }
}

plugins {
    id 'org.springframework.boot' version '2.6.5'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'com.ewerk.gradle.plugins.querydsl' version '1.0.10'		// queryDSL plugins 추가
    id 'java'
}

group = 'com.springboot2'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

configurations {
    compileOnly {
       extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    /* queryDSL */
    implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
    implementation "com.querydsl:querydsl-apt:${queryDslVersion}"
    implementation "com.querydsl:querydsl-core:${queryDslVersion}"
}

tasks.named('test') {
    useJUnitPlatform()
}

/* queryDSL 빌드 설정 추가 */
// queryDSL에서 사용할 경로 설정
def querydslDir = "$buildDir/generated/querydsl"

// JPA 사용 여부와 사용할 경로를 설정
querydsl {
    jpa = true
    querydslSourcesDir = querydslDir
}

// build 시 사용할 sourceSet 추가
sourceSets {
    main.java.srcDir querydslDir
}

// queryDSL 컴파일 시 사용할 옵션 설정
compileQuerydsl {
    options.annotationProcessorPath = configurations.querydsl
}

// queryDSL이 compileClassPath를 상속하도록 설정
configurations {
    compileOnly {
       extendsFrom annotationProcessor
    }
    querydsl.extendsFrom compileClasspath
}

/* 빌드 시 테스트 제외 */
test {
  exclude '**/*'
}

 

 

설정 후 JPAQueryFactory 생성 시 EntityManager를 넣어주도록 @Bean을 주입한다.

package com.springboot2.legacy.config;

import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.persistence.EntityManager;

@Configuration
public class JpaConfig {

  @Bean
  JPAQueryFactory jpaQueryFactory(EntityManager em) {
    return new JPAQueryFactory(em);
  }

}

 

 

 

이후 JPAQueryFactory를 통해 로직을 구성하면 된다.

package com.springboot2.legacy.service.first;

import com.querydsl.jpa.impl.JPAQueryFactory;
import com.springboot2.legacy.entity.first.PokemonEntity;
import com.springboot2.legacy.entity.first.QPokemonEntity;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;


@Service
@RequiredArgsConstructor
public class PokemonService {

  private final JPAQueryFactory queryFactory;

  public List<PokemonEntity> selectPokemon() {

    return queryFactory
      .selectFrom(QPokemonEntity.pokemonEntity)
      .fetch();
  }

}

 

 

테스트 후 정상 동작 확인

  @Autowired
  PokemonService pokemonService;

  @Test
  void firstDB() {
    List<PokemonEntity> pokemonEntities = pokemonService.selectPokemon();
    pokemonEntities.forEach(ent -> System.out.println("FIRST DB QueryDSL : " + ent.getPokemonId() + " : " + ent.getName()));

  }

 

 

이 설정은 스프링 부트 3.x 버전에선 변경해야 한다. 

해당 변경 사항은 오라클이 JavaEE를 이클립스 재단으로 넘기면서 기존 패키지명이 javax -> jakarta로 변경된 것과 관련있다. 이에 QueryDSL 라이브러리도 jakarta에 맞추어 변경된 것으로 보인다.

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.2'
    id 'io.spring.dependency-management' version '1.1.2'
/* 해당 플러그인이 부트3에서는 에러가 남 ( Attempt to recreate a file for type ~ ) */
//    id 'com.ewerk.gradle.plugins.querydsl' version '1.0.10'
}

group = 'com.springboot3'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

// queryDSL이 compileClassPath를 상속하도록 설정
configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {

	/* queryDSL */
    implementation "com.querydsl:querydsl-jpa:5.0.0:jakarta"
    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
    annotationProcessor "jakarta.annotation:jakarta.annotation-api"
    annotationProcessor "jakarta.persistence:jakarta.persistence-api"

}

tasks.named('test') {
    useJUnitPlatform()
}

/* queryDSL 설정 추가 */
/* 부트3에서는 Entity를 수정한 후, run을 하면 자동으로 QClass가 생성된다. */

// queryDSL에서 사용할 경로 설정
def querydslDir = "$buildDir/generated/querydsl"

sourceSets {
    main.java.srcDirs += [ querydslDir ]
}

tasks.withType(JavaCompile) {
    options.generatedSourceOutputDirectory = file(querydslDir)
}

clean.doLast {
    file(querydslDir).deleteDir()
}

/* 빌드 시 테스트 제외 */
test {
    exclude '**/*'
}

 

 

기존에는 querydsl plugin을 통하여 QType Class를 생성하였으나, 이제는 해당 플러그인이 없어도 알아서 QType Class를 생성한다.

 

 

때문에 querydsl plugin을 사용하게되면 QType Class가 두 번 생성되면서 에러가 발생하게 된다.

[ERROR] Attempt to recreate a file for type com.springboot3.db.entity.first.QPokemonEntity
[ERROR] Attempt to recreate a file for type com.springboot3.db.entity.second.QItemEntity

 

 

jakarta.annotation-api jakarta.persistence-api을 추가하지 않을 경우, 아래와 같은 에러가 발생하게 된다.

java.lang.NoClassDefFoundError:javax/persistence/Entity

 

 

동일하게 테스트 후 정상 동작하는지 확인하면 끝 😉

FIRST DB QueryDSL : 121 : Pikachu
FIRST DB QueryDSL : 122 : Bulbasaur
FIRST DB QueryDSL : 123 : Charmander
FIRST DB QueryDSL : 124 : Squirtle
FIRST DB QueryDSL : 125 : Butterfree
FIRST DB QueryDSL : 126 : Rattata
FIRST DB QueryDSL : 127 : Clefairy
FIRST DB QueryDSL : 128 : Arbok
FIRST DB QueryDSL : 129 : Diglett
FIRST DB QueryDSL : 130 : Kadabra

 

 

 

참고

 

https://post.dooray.io/we-dooray/tech-insight-ko/back-end/4173/