Spring Boot Jackson ResponseEntity 找不到类的序列化程序

Posted

技术标签:

【中文标题】Spring Boot Jackson ResponseEntity 找不到类的序列化程序【英文标题】:Spring Boot Jackson ResponseEntity No serializer found for class 【发布时间】:2020-07-26 02:32:36 【问题描述】:

我在使用 Spring Boot 控制器时遇到了一个奇怪的错误,没有返回最近创建的对象。

我有一个控制器,有两种方法(见下文)。一个简单的检索类“OrderPay”的对象并将其作为响应实体的有效负载返回。这工作正常,因此对象没问题。

另一个创建并保存“OrderPay”的新实例,然后应该返回那个新创建的对象。新对象的创建及其持久性工作正常。但是,当我尝试退货时,我收到以下错误消息。

现在我会理解该错误消息,如果它始终如一地发生。但是,当使用第一个函数(“getPaymentByIdTest”)返回这个新创建的对象时,它会毫无问题地返回它,即使我以完全相同的方式从数据库中检索它并以相同的方式返回它,具有相同的返回类型方法。

现在我知道在 HTTP-GET 方法中执行代码不是最佳实践,但它更快更方便测试。

谁能看到我需要在哪里调整代码?

2020-04-13 21:37:57.507 错误 26796 --- [nio-8081-exec-2] oaccC[.[.[/].[dispatcherServlet]:Servlet.service() 用于 servlet [dispatcherServlet]在路径 [] 的上下文中抛出异常 [请求处理失败;嵌套异常是org.springframework.http.converter.HttpMessageConversionException:类型定义错误:[简单类型,类org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor];嵌套异常是 com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties found to create BeanSerializer(为避免异常,禁用 SerializationFeature.FAIL_ON_EMPTY_BEANS)(通过参考链:com.brownbag_api.model.OrderPay["posSend"]->com.brownbag_api.model.Pos$HibernateProxy$7l7MDMEi["hibernateLazyInitializer"])] 根本原因

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor 也没有发现创建 BeanSerializer 的属性(为避免异常,禁用 SerializationFeature.FAIL_ON_EMPTY_BEANS)(通过参考链:com.brownbag_api.model.OrderPay["posSend"]->com.brownbag_api.model.Pos$HibernateProxy$7l7MDMEi["hibernateLazyInitializer"])

    控制器
@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/api/pay")
public class PaymentController 

    @Autowired
    private OrderPayRepo orderPayRepo;

    @Autowired
    private OrderPaySvc orderPaySvc;

    @GetMapping("/id")
    public ResponseEntity<?> getPaymentByIdTest(@PathVariable Long id) 
        Optional<OrderPay> orderPay = orderPayRepo.findById(id);
        return ResponseEntity.ok(orderPay);
    

    @GetMapping("/exec/from/from/to/to/amount/amount")
    public ResponseEntity<?> execPayment(@PathVariable Long from, @PathVariable Long to, @PathVariable double amount) 
        Pos posFrom = posRepo.getOne(from);
        Pos posTo = posRepo.getOne(to);
        OrderPay pay = orderPaySvc.createPay(amount, posFrom, posTo);
        pay = orderPaySvc.execPay(pay);

        if (pay == null) 
            return ResponseEntity.ok("Payment could not be executed. Please see log for more details!");
         else 
            System.err.println("Payment executed: " + pay.getPosRcv().getParty().getName());
            Long payId = pay.getId();
            System.err.println("Payment executed: " + payId);
            // payId returns the expected value here, the object is therefore saved in the database (verified).
            Optional<OrderPay> orderPay = orderPayRepo.findById(payId);
            return ResponseEntity.ok(pay);
        

    

    Order.java
@Entity
@Table(name = "order_base")
@Inheritance(strategy = InheritanceType.JOINED)
public class Order implements Serializable 

    private static final long serialVersionUID = -3458221490393509305L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    private Long id;

    @NotNull
    @Column(name = "QTY")
    private double qty;

    public Order() 
    

    public Order(@NotNull double qty) 
        super();
        this.qty = qty;
    

    订单支付
@Entity
@Table(name = "order_pay")
public class OrderPay extends Order implements Serializable 

    private static final long serialVersionUID = 4643589803146964779L;

    @NotNull
    @OneToOne(targetEntity = Pos.class)
    @JoinColumn(name = "POS_SEND_ID")
    private Pos posSend;

    @NotNull
    @OneToOne(targetEntity = Pos.class)
    @JoinColumn(name = "POS_RCV_ID")
    private Pos posRcv;

    public OrderPay() 
        super();
    

    public OrderPay(@NotNull double qty, @NotNull Pos posSend, @NotNull Pos posRcv) 

        super(qty);
        this.posSend = posSend;
        this.posRcv = posRcv;

    

    Pos.java
@Entity
@Table(name = "POS")
public class Pos implements Serializable 

    private static final long serialVersionUID = 1530699992135610397L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    private Long id;

    @NotNull
    @Column(name = "QTY")
    private double qty;

    @NotNull
    @ManyToOne(targetEntity = Party.class)
    @JoinColumn(name = "PARTY_ID")
    @JsonBackReference
    private Party party;

    public Pos() 
    

    public Pos(@NotNull double qty, @NotNull Party owner) 
        super();
        this.qty = qty;
        this.party = owner;
    

    JSON

"id":7,
"qty":33000.0,
"posSend":
  
  "id":1,
  "qty":-266010.0,
  "hibernateLazyInitializer":
  ,
"posRcv":
  
  "id":2,
  "qty":66000.0,
  "hibernateLazyInitializer":
  

【问题讨论】:

添加Pos类也 【参考方案1】:

如果您使用的是 Spring Boot,您可以在 application.properties 文件中设置以下属性。根据您的堆栈跟踪,这应该可以解决问题(请参阅:“为避免异常,禁用 SerializationFeature.FAIL_ON_EMPTY_BEANS”)

spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false

【讨论】:

这修复了错误,但在 JSON 文件中添加了一个新行。有没有没有这种副作用的替代品? 它为您添加了哪些额外的行?您能否将 JSON 添加到您的原始问题陈述中? 我添加了带有“hibernateLazyInitializer”附录的 JSON。它仅在初始创建时发生,并在使用第一个控制器方法获取对象时消失(即在创建后不立即调用它) 我通常从不使用与 JPA/Hibernate 相同的对象并将它们公开为 JSON 对象。通常我在两者之间有一个映射以确保它们不是同一个对象,所以我从来没有这个问题。 我明白了。我觉得这对我的应用程序来说可能有点矫枉过正,除非这样可以为我节省很多时间。请问您如何映射它们?您在 JSON 对象中是否有一个构造函数,它接收 JPA 对象作为参数并在 JSON 对象的构造函数中逐字段映射它?

以上是关于Spring Boot Jackson ResponseEntity 找不到类的序列化程序的主要内容,如果未能解决你的问题,请参考以下文章

Jackson 在我的 Spring Boot 应用程序中忽略了 spring.jackson.properties

如何在 Spring Boot 1.4 中自定义 Jackson

Spring Boot没有使用Jackson Kotlin插件

Spring Boot 未使用 Jackson Kotlin 插件

spring-boot用jackson改变json响应结构

Spring boot + Jackson + LocalDateTime:日期解析不正确