JpaRepository Custom / repository에 공통 사용 메서드 추가
JpaRepository의 메서드를 활용하면서, 공통으로 활용하는 메서드를 추가하기 위해 JpaRepository를 커스텀 하는 방법을 알아보겠습니다.
1. JpaRepository extends 한 CustomJpaRepository interface 작성
@NoRepositoryBean
public interface CustomJpaRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
/*추가로 작성할 메서드를 작성합니다.*/
JPAQueryFactory getQueryFactory();
}
@NoRepositoryBean 은 말 그대로 repository bean으로 등록하지 않겠다는 어노테이션 입니다.
JpaRespository를 상속받은 CustomJpaRepository interface를 작성합니다.
추가로 필요한 메서드들을 등록합니다.
getQueryFactory 메서드는 Querydsl을 쓰는 모든 repository에서 DI 받는 코드를 줄이기 위해 추가하였습니다.
동작은 하지만, 문제가 있을 수도 있으니 각 repository 마다 DI 해서 사용하세요.
2. CustomJpaRepository 의 구현체 CustomJpaRepositoryimpl 작성
public class CustomJpaRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID>
implements CustomJpaRepository<T, ID> {
private final Logger LOGGER = LoggerFactory.getLogger(CustomJpaRepositoryImpl.class);
private final EntityManager;
private final JPAQueryFactory;
public JpaDynamicSearchRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
this.queryFactory = new JPAQueryFactory(entityManager);
this.entityManager = entityManager;
}
/*추가로 작성해야 하는 메서드 구현*/
}
구현체에 @Repository 를 추가하면 아래와 같은 에러를 볼 수 있습니다. @Repository는 붙이지 마세요.
required a bean of type 'org.springframework.data.jpa.repository.support.JpaEntityInformation' that could not be found.
이는 CustomJpaRepositoryimpl이 bean으로 등록되는 시점에 JpaEntityInformation이 등록되지 않았기 때문입니다.
해당 문제를 해결하기 위해 JpaEntityInformation 대신 Class<T> 로 바꾸면 에러는 없어지지만 어플리케이션 실행 시 아래와 같은 에러를 보실 수 있습니다.
Parameter 0 of constructor in CustomJpaRepositoryImpl required a bean of type 'java.lang.Class' that could not be found.
'CustomJpaRepositoryimpl 생성자의 0 번째 파라미터 'java.lang.Class' 타입의 빈을 찾을 수 없다.' 는 말입니다.
Class<T>는 런타임에 제네릭 타입 정보를 유지하는 데 사용되며, 스프링 컨테이너에서는 이러한 유형의 빈을 직접적으로 관리하지 않기 때문입니다.
이제 @Repository를 제거하고 CustomJpaRepositoryimpl 을 repositoryBaseClass 로 설정하기위한 JpaConfig를 생성합니다.
Entity class가 필요하다면 위 클래스변수를 추가하고 생성자에 아래 코드 추가
this.entityClass = entityInformation.getJavaType();
PathBuilder가 필요하다면 클래스 변수를 추가하고 생성자에 아래 코드 추가 (QEntity)
this.pathBuilder = new PathBuilder<>(this.entityClass, this.entityClass.getSimpleName().toLowerCase());
3. @EnableJpaRepositories repositoryBaseClass 작성
@Configuration
@EnableJpaRepositories(repositoryBaseClass = CustomJpaRepositoryImpl.class)
public class JpaConfig {
}
설정을 추가함으로써 Spring Data JPA에서 커스텀한 CustomJpaRepositoryImpl 의 기능을 여러 레포지토리 상속해서 공유할 수 있습니다.
4. JpaRepository 를 CustomJpaRepository로 치환
기존에 extends 받던 JpaRepository 대신에 CustomJpaRepository로 변경합니다.
@Repository
public interface TestRepository extends CustomJpaRepository<TestEntity, Long> {
}
이제 CustomJpaRepository에 작성한 메서드를 여러 Repository에서 공유해서 사용할 수 있고, 기존 JpaRepository의 메서드를 Override 해서 사용할 수도 있습니다.