Java Stream 사용 시 Dto를 어떻게 작성해야할까?

임동혁 Ldhbenecia·2024년 4월 8일

SpringBoot

목록 보기
2/28
post-thumbnail

상황

현재 User의 Rank와 방 목록을 조회하는 API에서 findAll 로직을 구현하고 있다.

User Rank로 예시를 들어보려고 한다.

public List<UserRankDto> getUserRanks() {
    List<User> users = em.createQuery("SELECT u FROM User u ORDER BY u.score DESC", User.class)
            .getResultList();

    return users.stream()
            .map(UserRankDto::new)
            .collect(Collectors.toList());
}

현재 이 코드는 JPQL을 사용하여 User의 Score를 기준으로 내림차순으로 List를 뽑았고 이 User 객체를 UserRankDto로 매핑해서 반환한다.

UserRankDto

@Getter
public class UserRankDto {

    private String nickname;
    private int score;

    public UserRankDto(User user) {
        this.nickname = user.getNickname();
        this.score = user.getScore();
    }
}

이렇게 구성되어있다. 직접 생성자를 추가해주었다.

💡 Java에서는 클래스에 생성자가 정의되어 있을 때만 해당 클래스를 생성자 참조 :: 로 사용할 수 있다.
따라서 UserRankDto 클래스에는 파라미터가 없는 생성자를 추가해야 한다.


해당 생성자를 제거할 시 아래와 같은 에러를 확인할 수 있다.

error: incompatible types: invalid constructor reference
                .map(UserRankDto::new)
                     ^
    constructor UserRankDto in class UserRankDto cannot be applied to given types
      required: no arguments
      found:    User
      reason: actual and formal argument lists differ in len.....

@AllArgsConstructor로는 안될까?

결론부터 말하자면 불가능하다.

왜냐하면 현재 저 생성자는 User를 파라미터로 받아와서 User에서 반환할 Dto 내의 값들을 기록하고 있다.

public class UserRankDto {

    private String nickname;
    private int score;

    public UserRankDto(String nickname, int score) {
        this.nickname = user.getNickname();
        this.score = user.getScore();
    }
}

@AllArgsConstructor를 사용하면 이러한 생성자가 만들어지니 DB에서 가져온 User를 매핑할 때 사용할 수 없다.

결론적으로 stream 메서드만을 사용할 때 나는 @Getter 어노테이션 하나만 사용하였다.

틀린 사실이 있거나 추가적으로 알면 좋은 내용이 있으시다면 언제든지 댓글 부탁드립니다!

0개의 댓글