so2zy 프로젝트를 할때 발생한 Jackson 직렬화 제한자 문제이다. 코딩할 때 항상 “문제”를 겪을 수 밖에 없는 것 같다. 다양한 문제 상황을 겪으면서 기록하고 공유하면서 한걸음 성장해 나가는 것이 얼마나 중요한지 깨달아 가고 있다. 🌱
🔗 https://github.com/so2zy/so2zy_BE/discussions/29#discussion-5881119
발생과정
public RoomCartResponseDTO postRoomCart(Long member_id, Long room_id){
Room room = roomRepository.findById(room_id).get();
Cart cart = cartRepository.findByMemberId(member_id).get();
RoomCart roomCart = roomCartRepository.save(new RoomCart(cart,room));
cart.postRoomCarts(roomCart);
return new RoomCartResponseDTO(cart);
}
@OneToMany(mappedBy = "cart", fetch = FetchType.LAZY)
private List<RoomCart> roomCartList = new ArrayList<>();
public void postRoomCarts(RoomCart roomCart){
roomCartList.add(roomCart);
}
- 객실을 장바구니에 담을 때 RoomCart를 생성하여 cart의
List<RoomCart> roomCartList
에 post하고자 했다.
문제
Type definition error: [simple type, class com.aroom.domain.roomCart.dto.response.RoomCartResponseDTO]
org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.aroom.domain.roomCart.dto.response.RoomCartResponseDTO]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:489) ~[spring-web-6.0.13.jar:6.0.13]
at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:103) ~[spring-web-6.0.13.jar:6.0.13]
at
caused by: com.fasterxml.jackson.databind.exc.invaliddefinitionexception:
no serializer found for class com.aroom.domain.roomcart.dto.response.roomcartresponsedto
and no properties discovered to create beanserializer
(to avoid exception, disable serializationfeature.fail_on_empty_beans)
(through reference chain: com.aroom.global.response.apiresponse["data"])
- Jackson 라이브러리가
RoomCartResponseDTO
&RoomCartInfoDTO
를 직렬화할 때 문제가 발생했음
- Jackson은 기본적으로 클래스를 직렬화할 때 해당 클래스에 대한 직렬화 메소드를 찾아야 하는데, 여기서는 해당 메소드를 찾지 못했다고 나온다.
- 또한, Jackson은 직렬화 하는 과정에서 기본으로 접근 제한자가 public이거나, getter/setter를 이용하기 때문에 인스턴스 필드를 private등으로 선언시, json으로 변환 과정에서 에러가 발생한다.
해결방안
- JsonAutoDetect 설정 제거
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
- private 필드에 접근 가능하여 json으로 변환 가능하다.
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class RoomCartInfoDTO {
private long room_id;
private long cart_id;
@Builder
public RoomCartInfoDTO(long room_id, long cart_id) {
this.room_id = room_id;
this.cart_id = cart_id;
}
public RoomCartInfoDTO(RoomCart roomCart) {
this.room_id = roomCart.getRoom().getId();
this.cart_id = roomCart.getCart().getId();
}
}
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class RoomCartResponseDTO {
private long cart_id;
private List<RoomCartInfoDTO> roomCartList;
public RoomCartResponseDTO(Cart cart) {
this.cart_id = cart.getId();
List<RoomCartInfoDTO> roomCartInfoDTOList = new ArrayList<>();
for(RoomCart roomCart : cart.getRoomCartList()){
RoomCartInfoDTO roomCartInfoDTO = new RoomCartInfoDTO(roomCart);
roomCartInfoDTOList.add(roomCartInfoDTO);
}
System.out.println(roomCartInfoDTOList.size()); // 정확히 나옴
this.roomCartList = roomCartInfoDTOList;
}
}
왜 이렇게 해결?
- Fetch.Type을 EAGER로 바꾸는 것은 보안의 문제가 있으므로 고려하지 않았습니다.
- 또한, Entity Class에 @JsonProperty 또는 @JsonAutoDetect를 직접 선언할 수 있으나, Entity를 최대한 변경하지 않고자 DTO에 선언했습니다.
🔗 참고 URL
https://steady-hello.tistory.com/90
Uploaded by N2T