2024. 10. 19. 20:45ㆍSpring Boot/Spring Data JPA
Spring Data JPA는 여러 결과를 리턴하는 쿼리 메서드에서 다양한 Java 컬렉션 타입을 사용할 수 있습니다. 여기서는 Iterable
, List
, Set
와 같은 표준 Java 컬렉션 타입 외에도, Spring Data의 Streamable
이라는 커스텀 Iterable 확장 타입과 Vavr 라이브러리에서 제공하는 컬렉션 타입을 지원합니다. 이 섹션에서는 이러한 리턴 타입에 대해 자세히 설명하겠습니다.
Streamable을 쿼리 메서드 리턴 타입으로 사용하기
Streamable
은 Iterable
또는 기타 컬렉션 타입의 대안으로 사용할 수 있습니다. Streamable
은 non-parallel Stream에 접근할 수 있는 편의 메서드를 제공하고, 직접 .filter(…)
, .map(…)
와 같은 연산을 수행할 수 있습니다. 또한 다른 Streamable
객체와 연결(concatenate)할 수 있는 기능도 제공합니다.
예시: Streamable로 쿼리 메서드 결과 결합하기
interface PersonRepository extends Repository<Person, Long> {
Streamable<Person> findByFirstnameContaining(String firstname);
Streamable<Person> findByLastnameContaining(String lastname);
}
// 사용 예
Streamable<Person> result = repository.findByFirstnameContaining("av")
.and(repository.findByLastnameContaining("ea"));
위 예시에서, findByFirstnameContaining
메서드는 주어진 이름이 포함된 사람들을 찾고, findByLastnameContaining
메서드는 주어진 성이 포함된 사람들을 찾습니다. 두 Streamable
결과는 and
메서드를 통해 결합됩니다.
사용자 정의 Streamable 래퍼 리턴
컬렉션을 위한 전용 래퍼 타입을 제공하는 것은 여러 요소를 리턴하는 쿼리 결과를 API로 제공하는 일반적인 패턴입니다. 이러한 타입은 컬렉션과 유사한 타입을 리턴하는 리포지토리 메서드를 호출하고, 수동으로 래퍼 타입의 인스턴스를 생성하여 사용됩니다. Spring Data는 이러한 래퍼 타입을 쿼리 메서드 리턴 타입으로 사용할 수 있게 해주는데, 다음 조건을 만족해야 합니다:
- 타입이
Streamable
을 구현해야 합니다. - 타입이
Streamable
을 아규먼트로 받는 생성자 또는of(…)
또는valueOf(…)
라는 이름의 정적 팩토리 메서드를 노출해야 합니다.
예시
class Product { // (1)
MonetaryAmount getPrice() { … }
}
@RequiredArgsConstructor(staticName = "of")
class Products implements Streamable<Product> { // (2)
private final Streamable<Product> streamable;
public MonetaryAmount getTotal() { // (3)
return streamable.stream()
.map(Product::getPrice)
.reduce(Money.of(0), MonetaryAmount::add);
}
@Override
public Iterator<Product> iterator() { // (4)
return streamable.iterator();
}
}
interface ProductRepository extends Repository<Product, Long> {
Products findAllByDescriptionContaining(String text); // (5)
}
Product
엔티티는 제품 가격에 접근하는 API를 노출합니다.Products
는Streamable<Product>
에 대한 래퍼 타입으로,Products.of(…)
메서드를 사용하여 생성할 수 있습니다. 표준 생성자도 가능합니다.- 이 래퍼 타입은
Streamable<Product>
에서 새로운 값을 계산하는 추가 API를 제공합니다. Streamable
인터페이스를 구현하고 실제 결과에 위임(delegate)합니다.Products
래퍼 타입을 쿼리 메서드 리턴 타입으로 직접 사용할 수 있습니다. 즉,Streamable<Product>
를 리턴하고 결과를 수동으로 래핑할 필요가 없습니다.- @RequiredArgsConstructor
Vavr 컬렉션 지원
Vavr는 Java에서 함수형 프로그래밍 개념을 수용하는 라이브러리로, 여러 커스텀 컬렉션 타입을 제공합니다. Vavr의 컬렉션 타입을 쿼리 메서드 리턴 타입으로 사용할 수 있으며, 다음 표와 같이 매핑됩니다:
Vavr 컬렉션 타입 | 사용된 Vavr 구현 타입 | 유효한 Java 소스 타입 |
---|---|---|
io.vavr.collection.Seq |
java.util.Iterable |
|
io.vavr.collection.List |
java.util.Iterable |
|
io.vavr.collection.Set |
java.util.Iterable |
|
io.vavr.collection.LinkedHashSet |
java.util.Iterable |
|
io.vavr.collection.Map |
java.util.Map |
|
io.vavr.collection.LinkedHashMap |
java.util.Map |
위 표의 첫 번째 열에 있는 타입(또는 그 하위 타입)을 쿼리 메서드 리턴 타입으로 사용하면, 두 번째 열의 타입이 구현 타입으로 사용됩니다. 쿼리 결과의 실제 Java 타입(세 번째 열)에 따라 달라집니다. 또는 Traversable
(Vavr의 Iterable 동등 타입)을 선언할 수 있으며, 이 경우 실제 리턴값에 따라 구현 클래스를 파생합니다. 즉, java.util.List
는 Vavr의 List
또는 Seq
로 변환되고, java.util.Set
은 Vavr의 LinkedHashSet
으로 변환됩니다.
이와 같이 Spring Data는 다양한 컬렉션 타입을 지원하여 더 유연하고 기능적인 쿼리 메서드를 제공합니다.
'Spring Boot > Spring Data JPA' 카테고리의 다른 글
Paging, Iterating Large Results, Sorting & Limiting (0) | 2024.10.20 |
---|---|
Streaming Query Results, Asynchronous Query Results (0) | 2024.10.20 |
Property Expressions (0) | 2024.10.19 |
Reserved Method Names (1) | 2024.10.19 |
Query Creation (0) | 2024.10.19 |