14. DTO 생성자 누락으로 인해 Native Query 결과 파싱 중 오류

김미숙's avatar
Jul 15, 2025
14. DTO 생성자 누락으로 인해 Native Query 결과 파싱 중 오류
pakage com.metacoding.bankv1.account; import com.metacoding.bankv1.user.User; import lombok.Data; import java.util.List; public class AccountResponse { @Data public static class DetailDTO { private String fullname; private int number; private int balance; private List<HistoryDTO> histories; public DetailDTO(User sessionUser, Account account, List<HistoryDTO> histories) { this.fullname = sessionUser.getFullname(); this.number = account.getNumber(); this.balance = account.getBalance(); this.histories = histories; } } // 두번째 쿼리 @Data public static class HistoryDTO { private String createdAt; private int withdrawNumber; private int depositNumber; private int amount; private int balance; private String type; } }
public List<AccountResponse.HistoryDTO> findByAllNumber(Integer number) { Query query = em.createNativeQuery("select substr(created_at,1,16) created_at, withdraw_number, deposit_number, amount, case when withdraw_number = ? then withdraw_balance else deposit_balance end as \"balance\", case when withdraw_number = ? then '출금' else '입금' end as \"type\" from history_tb where withdraw_number = ? or deposit_number = ?"); query.setParameter(1, number); query.setParameter(2, number); query.setParameter(3, number); query.setParameter(4, number); List<Object[]> objectList = (List<Object[]>) query.getResultList(); List<AccountResponse.HistoryDTO> historyList = new ArrayList<>(); for (Object[] objects : objectList) { AccountResponse.HistoryDTO historyDTO = new AccountResponse.HistoryDTO( (String) objects[0], (int) objects[1], (int) objects[2], (int) objects[3], (int) objects[4], (String) objects[5] ); historyList.add(historyDTO); } return historyList; }

문제 원인

  1. HistoryDTO 클래스에는 생성자가 없음
    1. HistoryDTO 클래스는 @Data 애너테이션을 사용하고 있지만, 명시적인 생성자가 없기 때문에 기본 생성자만 자동으로 생성됩니다.
      그러나 for 루프에서는 new AccountResponse.HistoryDTO(...)를 통해 인스턴스를 생성하려고 하므로, 해당 생성자가 없어서 컴파일 오류 또는 런타임 오류가 발생할 수 있습니다.
  1. 타입 변환 문제
      • (int) objects[1] 같은 형변환에서 문제가 발생할 가능성이 있습니다.
      • objects[1], objects[2], objects[3], objects[4] 등이 Integer, BigDecimal, Long 등의 타입으로 반환될 수 있습니다.
      • String으로 저장된 숫자를 (int)로 변환하면 ClassCastException이 발생할 수도 있습니다.

🛠 해결 방법

1. HistoryDTO에 생성자 추가

  • AccountResponse.HistoryDTO 클래스에 필요한 모든 필드를 받는 생성자를 추가
    • @Data public static class HistoryDTO { private String createdAt; private int withdrawNumber; private int depositNumber; private int amount; private int balance; private String type; public HistoryDTO(String createdAt, int withdrawNumber, int depositNumber, int amount, int balance, String type) { this.createdAt = createdAt; this.withdrawNumber = withdrawNumber; this.depositNumber = depositNumber; this.amount = amount; this.balance = balance; this.type = type; } }

2. 타입 변환 문제 해결

JPA의 createNativeQuery()는 필드 값을 Object[] 형태로 반환하는데, 숫자 값이 BigDecimal 또는 Long으로 반환될 수 있습니다.
따라서 (int) objects[i] 대신에 ((Number) objects[i]).intValue() 를 사용하면 타입 변환 문제를 방지할 수 있습니다.
  • 수정된 코드
    • for (Object[] objects : objectList) { AccountResponse.HistoryDTO historyDTO = new AccountResponse.HistoryDTO( (String) objects[0], ((Number) objects[1]).intValue(), ((Number) objects[2]).intValue(), ((Number) objects[3]).intValue(), ((Number) objects[4]).intValue(), (String) objects[5] ); historyList.add(historyDTO); }

결론

  1. HistoryDTO 클래스에 모든 필드를 받는 생성자를 추가
  1. (int) objects[i] 대신 ((Number) objects[i]).intValue() 를 사용하여 타입 변환 문제를 해결
Share article

parangdajavous