无法反序列化从 Springboot POST 映射函数上的 Angular http post 请求发送的 POJO

Posted

技术标签:

【中文标题】无法反序列化从 Springboot POST 映射函数上的 Angular http post 请求发送的 POJO【英文标题】:Can't deserialize my POJO sent from an Angular http post request on my Springboot POST mapped function 【发布时间】:2020-12-08 02:02:36 【问题描述】:

就上下文而言,我的应用程序是一家咖啡店,我想将一系列项目发送到我的 springboot 后端。但是杰克逊给出了例外:

Cannot construct instance of `me.andrewq.coffeeshop.menu_items.Menu` 
(no Creators, like default constructor, exist): cannot deserialize from Object value 
(no delegate- or property-based Creator)
at [Source: (PushbackInputStream); line: 1, column: 3] (through reference chain: 
java.util.ArrayList[0])] with root cause
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 
Cannot construct instance of `me.andrewq.coffeeshop.menu_items.Menu` 
(no Creators, like default constructor, exist): cannot deserialize from Object value 
(no delegate- or property-based Creator)
at [Source: (PushbackInputStream); line: 1, column: 3] (through reference chain: 
java.util.ArrayList[0]).

这是项目的类的样子(省略了 setter 和 getter 之后):

public class Menu 

    private int productId;

    private String name;

    private double price;

    private String[][] productOptions;

    private String type;

    // These 3 variables belong to drinks. The creams and sugars more so for coffees
    private String currentSize;

    private Integer creams;

    private Integer sugars;


    public Menu(int productId, String name, double price, String productOptions, String type)
        this.productId = productId;
        this.name = name;
        this.price = price;
        this.productOptions = convertOptions(productOptions);
        this.type = type;
    

    /**
     * Used for converting the product options which is a key-value pair seperated by a ',' in the DB, into a 2D array in this class.
     * @param options
     * @return
     */
    private String[][] convertOptions(String options) 
        String[] optionPairs = options.split(",");

        //hard coded b/c I know that these are pairs 
        String retVal[][] = new String[optionPairs.length][2];

        for(int i = 0; i < optionPairs.length; ++i)
            String[] temp = optionPairs[i].split(":");
            retVal[i] =  temp;
        

        return retVal;
    
 
    @Override
    public String toString()

        return String.format("productId: %i, name: %s", this.productId, this.name);
    


请求在控制器类中被接收为:

@RestController
public class OrderController 
    
    @CrossOrigin(origins = "http://localhost:4200")
    @PostMapping(path = "/guestOrder")
    public String order(@RequestBody List<Menu> order)
        
        for(Menu item: order)
            System.out.println(item.toString());
        
        
        return "Sending order worked";
    

在 Angular 中,项目定义为:

export interface Menu 
    productId: number;

    name: string;
    
    price: number;
    
    productOptions: string[][];
    
    type: string;

    // additional field for drinks and coffees
    currentSize: string;

    creams: number;

    sugars: number;

http 请求调用是: this.http.post&lt;string&gt;(`$this.url/guestOrder`, this.orderItems); 其中http: HttpClientorderItems: Menu[]

如果不对 JSON 进行格式化,JSON 字符串的第 65 列会出现错误:

["productId":1,"name":"Iced Coffee","price":2,"productOptions":[["S","2.00"],["M","2.50"],["L","3.00"]],"type":"IC","currentSize":"S","creams":0,"sugars":0]

这是productOptions的第一个括号

【问题讨论】:

您确定这是正在传递的精确 JSON 字符串吗?您提到的异常表示它希望将 productOptions 元素解析为字符串而不是数组,这未反映在您提供的 JSON 中。此外,它说明了第 1 行第 65 列,但第 1 行没有第 65 列,这使得调试更加困难(也许您已格式化 JSON?如果是,请提供原始未格式化文本)。 是的,抱歉,我在发帖之前已经对文本进行了格式设置以提高可读性,但我在帖子底部的正文中插入了 JSON 的实际行。显然错误发生在 productOptions 属性的第一个左括号“[”。 感谢您的澄清。在这种情况下,JSON 匹配错误消息中的位置,但仍然没有解释为什么它要解析一个字符串,它应该解析一个数组。 JSON 对我来说看起来不错,并且似乎与您的 POJO 相匹配。是否有可能您的 Java 代码中的 productOptions 在早期版本中作为纯字符串(而不是 String[][])并且没有正确重新编译或重新部署? 我运行了mvn clean,然后运行了mvn spring-boot:run,错误实际上已更改为与无法创建Menu 对象有关的内容。我将在帖子的下一个例外中进行编辑。 感谢您的新输入 - 现在它实际上比第一次要容易得多 :-) 另外请修复您的帖子格式 - 您一定在编辑时弄乱了结束格式标签。第一次还不错。 【参考方案1】:

这个异常实际上说得很好——你需要为你的 POJO 类添加一个默认构造函数。

JSON 解析器首先创建一个空实例,然后为 JSON 文本中遇到的每个属性调用 setter 方法。 JSON 中未包含的属性保持不变,因此具有默认构造函数分配给它的值(通常是 null,除非您将其设置为其他值)。

我希望为清楚起见省略你所说的 getter 和 setter,确实存在,否则它不会工作。

【讨论】:

以上是关于无法反序列化从 Springboot POST 映射函数上的 Angular http post 请求发送的 POJO的主要内容,如果未能解决你的问题,请参考以下文章

如何修改 Spring Cloud AWS 用来反序列化 SQS 消息的对象映射器?

JSON 解析错误:无法反序列化 START_ARRAY 令牌中的实例

无法从 START_OBJECT 令牌中反序列化 `java.lang.Long` 的实例;在 Spring Boot 帖子上

Spring boot,Jackson Json 在序列化和反序列化时出现问题

无法读取文档:无法从 START_OBJECT 令牌中反序列化 java.lang.String 的实例

JSON 解析错误:无法从 START_OBJECT 令牌中反序列化 java.util.ArrayList 的实例