存在公共Setter时Jackson仍无法反序列化对象的原因
实体类定义
我定义了如下JPA实体类DummyEntity,包含公共无参构造方法及所有属性的Getter、Setter:
package com.example.demo.DummyObject; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.persistence.*; import java.io.IOException; import java.util.Date; import java.util.Map; /** * An entity containing analyzed data * * @author Thorvas */ @Entity @Table(name="DUMMY_ENTITY") public class DummyEntity { public DummyEntity() { } @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; @Column(name = "name") private String name; @ElementCollection private Map<String, Integer> population; @Column(name = "estimation") private int estimation; @Column(name = "last_updated") @Temporal(TemporalType.DATE) @JsonFormat(pattern = "yyyy-MM-dd") @JsonProperty("last_updated") private Date lastUpdated; public String getName() { return name; } public void setName(String name) { this.name = name; } public Map<String, Integer> getPopulation() { return population; } public void setPopulation(Map<String, Integer> population) { this.population = population; } public int getEstimation() { return estimation; } public void setEstimation(int estimation) { this.estimation = estimation; } public Date getLastUpdated() { return lastUpdated; } public void setLastUpdated(Date lastUpdated) { this.lastUpdated = lastUpdated; } public int getId() { return id; } public void setId(int id) { this.id = id; } }
提交的请求JSON
向POST接口提交如下JSON数据:
{ "name": "Powiat ząbkowicki", "population": { "2013": 67875, "2014": 67458, "2015": 66971, "2016": 66527, "2017": 66009, "2018": 65428, "2019": 64802, "2020": 62561, "2021": 61846, "2022": 61087 }, "estimation": 0, "last_updated": "2023-06-09" }
出现的反序列化错误
收到Jackson反序列化错误:
no String-argument constructor/factory method to deserialize from String value ('{"name": "Powiat ząbkowicki", "population": {"2013": 67875, "2014": 67458, "2015": 66971, "2016": 66527, "2017": 66009, "2018": 65428, "2019": 64802, "2020": 62561, "2021": 61846, "2022": 61087}, "estimation": 0, "last_updated": "2023-06-09"}')]
临时解决方法
添加带String参数的构造方法后问题解决:
public DummyEntity(String json) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); DummyEntity dummyEntity = objectMapper.readValue(json, DummyEntity.class); this.name = dummyEntity.name; this.population = dummyEntity.population; this.estimation = dummyEntity.estimation; this.lastUpdated = dummyEntity.lastUpdated; }
问题根源与解答
你遇到的问题根本不是实体类缺少Setter,而是Jackson接收到的输入格式不对:
实际输入是字符串而非JSON对象:错误信息明确显示Jackson试图把一个完整的JSON字符串直接反序列化成
DummyEntity,这说明请求的Content-Type可能不是application/json(比如是text/plain),或者请求发送方错误地将JSON对象转成了字符串(比如前端重复调用JSON.stringify,导致整个JSON被包裹成了字符串)。Jackson的默认反序列化逻辑:当Jackson收到字符串类型的输入,而目标类没有对应的String参数构造方法或工厂方法时,就会抛出这个错误。你的实体类本身满足Jackson正常反序列化的要求(无参构造+公共Setter),只要输入是正确的JSON对象且Content-Type为
application/json,不需要额外构造方法就能正常完成反序列化。临时解决方法的本质:你添加的String构造方法相当于绕开了输入格式错误——把收到的字符串重新解析成JSON对象再赋值给实体类属性,这只是规避了问题,并非真正修复根源。
正确的解决方式是检查请求的Content-Type是否设置为application/json,同时确保请求发送方直接发送JSON对象而非字符串化后的JSON。
内容的提问来源于stack exchange,提问作者Thorvas

