본문 바로가기

Development/Spring

[Spring] Spring JPA에서 null을 리턴 하지 않는 경우와 Optional 타입에 대하여

프로젝트를 진행하다가 JPA 메서드 리턴 타입에 Optional 래퍼 클래스를 씌운 적이 있는데,

이게 알고보니 JPA에서 null을 리턴하지 않는 메서드에다가도 적용을 했었던 의미 없는 변경을 한 적이 있습니다.

이 글에서는 Spring JPA에서 리턴 타입에 관해 작성해보고자 합니다.

Optional Class

Optional<T> Null이 아닌 값을 포함하거나 포함하지 않을 수 있는 컨테이너 객체를 나타내는 Java 클래스입니다. 값이 존재하는 경우 `isPresent()` 메서드는 `true`를 반환하며, `get()` 메서드는 해당 값을 반환합니다.

값의 존재 여부에 따라 의존하는 추가 메서드도 제공됩니다. 예를 들어, 값이 존재하지 않을 때 기본값을 반환하는 `orElse()` 메서드나 값이 존재할 때 코드 블록을 실행하는 `ifPresent()`와 같은 메서드 등이 있습니다.

이 클래스는 값 기반 클래스(value-based class)로, Optional의 인스턴스에 대한 동일성에 민감한(==, identity hash code, 또는 동기화와 관련된) 연산의 사용은 예측할 수 없는 결과를 낳을 수 있으며 피해야 합니다.

 

즉, Optional 인스턴스 간의 동일성 검사나 동기화와 같은 연산은 권장되지 않습니다.

Spring Data JPA

Spring Data JPA은 더 큰 Spring Data 패밀리의 일부로, JPA 기반(Java Persistence API) 레포지토리를 쉽게 구현할 수 있게 해 줍니다. 이는 데이터 액세스 기술을 사용하는 Spring 기반 애플리케이션을 구축하기를 더욱 쉽게 만들어줍니다.

애플리케이션의 데이터 액세스 레이어를 구현하는 것은 상당히 까다로울 수 있습니다. 가장 간단한 쿼리를 실행하려면 너무 많은 보일러플레이트 코드를 작성해야 합니다. 페이지네이션, 감사 및 기타 자주 필요한 옵션과 같은 것들을 추가하면 더욱 복잡해집니다.

Spring Data JPA는 데이터 액세스 레이어의 구현을 실제로 필요한 양으로 줄이는 것을 목표로 합니다. 개발자는 다양한 기술을 사용하여 레포지토리 인터페이스를 작성하고, Spring은 자동으로 연결해 줍니다. 사용자 정의 파인더나 예제를 사용하여 쿼리를 작성할 수도 있으며, Spring이 대신 쿼리를 작성해 줍니다.

Null Handling of Repository Methods

Spring Data 2.0 이후에는 Repository CRUD 메소드 중 단일 인스턴스(예를 들어, 결과가 단 하나인 쿼리)를 반환하는 경우, Java 8의 Optional을 사용하여 값이 잠재적으로 없음을 나타낼 수 있습니다.


Query 메소드는 전혀 래퍼 유형을 사용하지 않을 수 있습니다. 이 경우, Query 결과가 없을 때는 null을 반환하여 나타냅니다.

그런데 Collection, Stream과 같은 타입을 반환하는 Repository 메소드는 null 대신 해당하는 비어 있는 값(예를 들어, List 타입이면 [])을 반환하도록 보장됩니다. 

Bad Practice

public interface AnsweredQuestionRepository extends
    JpaRepository<AnsweredQuestion, AnsweredQuestionId> {
    @Query("SELECT aq FROM AnsweredQuestion aq WHERE aq.answeredQuestionId.surveyId = :surveyId")
    Optional<List<AnsweredQuestion>> findAllBySurveyId(UUID surveyId);

 

다음과 같이 DB에서 설문조사 ID로 그 설문조사에 대한 모든 답변을 찾는 메소드가 있습니다.

Spring JPA에서 findAll은 List를 반환하므로, null을 반환하지 않습니다. 

Optional 로 감싸는 것은 의미가 없는 수정이었죠.. 그래서 이후엔 다시 Optional을 없앴습니다.

참고 자료

https://spring.io/projects/spring-data-jpa

 

Spring Data JPA

Spring Data JPA, part of the larger Spring Data family, makes it easy to easily implement JPA-based (Java Persistence API) repositories. It makes it easier to build Spring-powered applications that use data access technologies. Implementing a data access l

spring.io

https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html

 

Optional (Java Platform SE 8 )

A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value. Additional methods that depend on the presence or absence of a contained value are provided, such as orEl

docs.oracle.com