강의

멘토링

로드맵

인프런 커뮤니티 질문&답변

김유정님의 프로필 이미지
김유정

작성한 질문수

실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화

"org.springframework.http.converter.HttpMessageConversionException: Type definition error 에러

작성

·

9K

0

학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.

1. 강의 내용과 관련된 질문을 남겨주세요.
2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.
(자주 하는 질문 링크: https://bit.ly/3fX6ygx)
3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.
(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)

질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.
=========================================
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예/아니오)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)

[질문 내용]
안녕하세요 강사님, 강의를 진행하는 도중 에러가 발생하여 글 남깁니다.
 
<postman>
http://localhost:8080/api/v2/simple-orders
 
<error 메시지>
{ "timestamp": "2022-01-25T07:53:01.075+00:00", "status": 500, "error": "Internal Server Error", "trace": "org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class jpabook1.jpashop1.api.OrderSimpleApiController$SimpleOrderDto]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class jpabook1.jpashop1.api.OrderSimpleApiController$SimpleOrderDto and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0])\n\tat org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:460)\n\tat org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:104)\n\tat org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:290)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:183)\n\tat org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:78)\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:135)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\n\tat org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:655)\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:764)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732)\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\n\tat java.base/java.lang.Thread.run(Thread.java:831)\nCaused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class jpabook1.jpashop1.api.OrderSimpleApiController$SimpleOrderDto and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0])\n\tat com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)\n\tat com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1300)\n\tat com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400)\n\tat com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:46)\n\tat com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:29)\n\tat com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:145)\n\tat com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:107)\n\tat com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25)\n\tat com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)\n\tat com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:400)\n\tat com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1514)\n\tat com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1007)\n\tat org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:454)\n\t... 48 more\n", "message": "Type definition error: [simple type, class jpabook1.jpashop1.api.OrderSimpleApiController$SimpleOrderDto]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class jpabook1.jpashop1.api.OrderSimpleApiController$SimpleOrderDto and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0])", "path": "/api/v2/simple-orders" }
 
 
<OrderSimpleApiController.java>
@RestController
@RequiredArgsConstructor
public class OrderSimpleApiController {

private final OrderRepository orderRepository;

/**
* 주문 조회
*/
@GetMapping("/api/v2/simple-orders")
public List<SimpleOrderDto> ordersV2() {
//Order 테이블 조회 (결과 2개)
List<Order> orders = orderRepository.findAllByCriteria(new OrderSearch());
List<SimpleOrderDto> result = orders.stream()
.map(o -> new SimpleOrderDto(o))
.collect(Collectors.toList());

return result;
}

//DTO로 변환
static class SimpleOrderDto {
private Long orderId;
private String name;
private LocalDateTime orderDate;
private OrderStatus orderStatus;
private Address address;

//생성자
public SimpleOrderDto(Order order) {
orderId = order.getId();
name = order.getMember().getName(); //Member 테이블 조회
orderDate = order.getOrderDate();
orderStatus = order.getStatus();
address = order.getMember().getAddress(); //Delivery 테이블 조회
}
}


//fetch join으로 쿼리 1번 호출
@GetMapping("/api/v3/simple-orders")
public List<SimpleOrderDto> orderV3() {
List<Order> orders = orderRepository.findAllWithMemberDelivery();
List<SimpleOrderDto> result = orders.stream()
.map(o -> new SimpleOrderDto(o))
.collect(Collectors.toList());
return result;
}

}
 
<Order.java>
@Entity
@Table(name = "orders")
@Getter @Setter
public class Order {

@Id @GeneratedValue
@Column(name = "order_id")
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member;

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "delivery_id")
private Delivery delivery;

@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<>();

private LocalDateTime orderDate;

@Enumerated(EnumType.STRING)
private OrderStatus status; //ORDER, CANCEL


//연관관계 편의 메서드
public void setMember(Member member) {
this.member = member;
member.getOrders().add(this);
}

public void addOrderItem(OrderItem orderItem) {
this.orderItems.add(orderItem);
orderItem.setOrder(this);
}

public void setDelivery(Delivery delivery) {
this.delivery = delivery;
delivery.setOrder(this);
}

//생성 메서드
public static Order createOrder(Member member, Delivery delivery, OrderItem... orderItems) {
Order order = new Order();
order.setMember(member);
order.setDelivery(delivery);
for(OrderItem orderItem : orderItems) {
order.addOrderItem(orderItem);
}
order.setOrderDate(LocalDateTime.now());
order.setStatus(OrderStatus.ORDER);
return order;
}

//비즈니스 로직 (주문 취소)
public void cancel() {
if(delivery.getStatus() == DeliveryStatus.COMP) {
throw new IllegalStateException("이미 배송완료된 상품은 취소가 불가능합니다.");
}

this.setStatus(OrderStatus.CANCEL);

for(OrderItem orderItem : orderItems) {
orderItem.cancel(); //Item의 stockQuantity를 늘리기 위해 orderItem을 이용 (orderItem과 Item이 연관관계니깐)
}
}

//조회 로직(전체 주문 가격)
public int getTotalPrice() {
int totalPrice = 0;
for(OrderItem orderItem : orderItems) {
totalPrice += orderItem.getTotalPrice();
}
return totalPrice;
}

protected Order() {}

}
 
<Delivery.java>
@Entity
@Getter @Setter
public class Delivery {

@Id @GeneratedValue
private Long id;

@OneToOne(mappedBy = "delivery", fetch = FetchType.LAZY)
@JsonIgnore
private Order order;

@Embedded
private Address address;

@Enumerated(EnumType.STRING)
private DeliveryStatus status; //READY, COMP
}
 
<Member.java>
@Entity
@Getter @Setter
public class Member {

@Id @GeneratedValue
@Column(name = "member_id")
private Long id;

private String name;

@Embedded
private Address address;

@JsonIgnore
@OneToMany(mappedBy = "member") //Order클래스의 member 필드에 의해 mapped by 되는거야!
private List<Order> orders = new ArrayList<>();
}


 
<OrderItem.java>
@Entity
@Getter @Setter
public class OrderItem {

@Id @GeneratedValue
@Column(name = "order_item_id")
private Long id;

@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_id")
private Order order;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "item_id")
private Item item;

private int orderPrice;
private int count;

//생성 메서드
public static OrderItem createOrderItem(Item item, int orderPrice, int count) {
OrderItem orderItem = new OrderItem();
orderItem.setItem(item);
orderItem.setOrderPrice(orderPrice);
orderItem.setCount(count);

item.removeStock(count);

return orderItem;
}

//비즈니스 로직(주문취소)
public void cancel() {
item.addStock(count);
}

//조회 로직(전체 주문 가격)
public int getTotalPrice() {
return orderPrice * count;
}

protected OrderItem() {}
}

 

양방향 연관관계가 걸린 한쪽에 @JsonIgnore을 작성하였지만 에러가 계속 발생하여 문의 드립니다.

항상 강의 잘 듣고 있습니다. 감사합니다.

 

답변 1

0

안녕하세요. 김유정님, 공식 서포터즈 OMG입니다.

아래 링크를 참고해주세요.

링크와 동일한 문제로 보입니다.

https://www.inflearn.com/questions/267403

추가로 제공해드리는 전체 프로젝트 코드로도 실행하여 확인해주세요. 

감사합니다.

김유정님의 프로필 이미지
김유정

작성한 질문수

질문하기