코드 복사/붙여넣기 하는 당신이 아름답습니다.

JPA가 자랑하는 장점 중 하나인 respository interface를 코틀린에서 사용하면 조금 짜증나는 상황이 발생한다.

interface SometingRepository : CrudRepository<Something, Long> {
    // (1) fun findById(id: Long): Something?
    // (2) fun findByIdAndActiveIsTrue(id: Long): Something?
}
val entity = somethingRespoitory.findById(id);

여기서 entity의 type은 Optional<T>이다. 왜냐면 interface가 Optional<T> findById(ID var1); 이렇게 생겼기 때문이다.

이 interface는 Optional<Something!>를 뱉는다. 그러면 어떤 문제가 벌어질까?

entity.get()으로 그 안에 들어있는 데이터를 가져올 수 있다.

/**
* If a value is present, returns the value, otherwise throws
* {@code NoSuchElementException}.
*
* @apiNote
* The preferred alternative to this method is {@link #orElseThrow()}.
*
* @return the non-{@code null} value described by this {@code Optional}
* @throws NoSuchElementException if no value is present
*/
public T get() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}

만약 find 결과가 없어서 반환할 게 없으면 null을 뱉는 게 아니고 Exception을 던져버린다.

val data = somethingRepository.findById(id);

이렇게 되면 좋겠는데

val entity = somethingRespoitory.findById(id);
val data: Something?
try {
    data = entity.get()
} catch (e: Exception) {
    logger.error("serious?")
}

이렇게 해야 한다. (물론 자바에서는 항상 저렇게 해야 함)

그렇다고 (1)처럼 함수를 재정의 할 수도 없다. (오버라이딩도 안 됨)

그래서 (2)처럼 사용했다.

(근데 포스팅 쓰면서 알았는데 findAllById(Mutable)Iterable<Something!>을 뱉는다. ???)

wookje.kwon's profile image

wookje.kwon

2020-07-16 16:38

Read more posts by this author