오늘의 옷 프로젝트중 옷 검색 기능 중에, 공개 설정된 옷만 가져오도록 기능을 바꾸었다. 따라서, 처음에는 Slice
를 통해 가져온 데이터에 옷이 비공개인것만 그 리스트에서 삭제하려고 하고 아래와 같이 코드를 짰다.
@Override
public SliceDto<SearchResponse> searchByTag(SearchRequest request, Pageable pageable) {
Slice<Clothes> clothes = clothesRepository.searchByTag(request, pageable);
clothes.getContent().removeIf((Clothes::isLocked)); // 이후 문제가 되는 부분
return SliceDto.create(clothes.map(this::createSearchDtoResponse));
}
하지만, 테스트를 돌려보니까 다음과 같이 UnsupportedOperationException
에러가 났다. 불가능한 연산이라는 것인데, 어디서 올라온 예외인지 찾아보려고 인터페이스와 구현 클래스들을 찾아보아 나갔다.
먼저, Slice 인터페이스는 Streamable 인터페이스를 상속받고 있다.
Slice 인터페이스의 구현체인 SliceImpl 클래스는, Chunk 클래스를 상속받고 있다.
Chunck 클래스를 가보니 컨텐츠 필드가 보여서 내가 코드에서 사용했던 getContent()
함수를 찾아보니, Collections.unmodifiableList()
를 반환하고 있었다. 즉 말 그대로 변경 불가능한 리스트를 반환하고 있는 것이다.
마지막으로 Collections
클래스에 가보니,
add()
, remove()
, addAll()
과 같이 리스트의 값을 변경시킬 수 있는 모든 연산에 대해 UnsupportedOperationException 예외를 터트리고 있던 것이다.
따라서, Slice나 Page의 content의 값을 필터링 하거나 변경 시켜야 한다면, 새로 생성한 List에서 값을 처리 후 새로운 SliceImpl 객체에 변경된 리스트를 담아서 반환 시켜 주었다.
@Override
public SliceDto<SearchResponse> searchByKeyword(String keyword, Pageable pageable) {
Slice<Clothes> sliceEntity = this.clothesRepository.findByContentContaining(keyword, pageable);
//새로운 리스트 생성 후 필터링
List<Clothes> clothes = new ArrayList<>(sliceEntity.getContent());
clothes.removeIf(Clothes::isLocked);
//새로운 SliceImpl 객체 반환
return SliceDto.create(new SliceImpl<>(clothes, pageable, sliceEntity.hasNext()).map(this::createSearchDtoResponse));
}
"앞으로는 에러가 나면, 구글링 보다는 코드를 먼저 파헤쳐 보는 습관을 들이면 문제를 더 쉽게 해결할 수 있을 것 같다!"