Spring Boot JSON 没有反序列化到我的请求模型中
Posted
技术标签:
【中文标题】Spring Boot JSON 没有反序列化到我的请求模型中【英文标题】:SpringBoot JSON not deserializing into my request model 【发布时间】:2021-06-10 23:59:39 【问题描述】:我正在使用 SpringBoot 并尝试反序列化 JSON,例如:
"userId": "Dave",
"queryResults":
"id": "ABC",
"carData": .....,
"carId": "Honda",
"status": 0,
"model": "X"
,转入MyRequestModel
类:
public class MyRequestModel
private String userId;
private String: queryResults;
,在我的@PostMapping
方法中作为@RequestBody
参数接收,如下所示:
@PostMapping
public String postDate(@RequestBody MyRequestModel data)
...
return "posted";
上面的queryResults
字段应该作为CLOB存储在数据库中。
我遇到的问题是,如果我将此 JSON 发送到我的端点 (PostMapping) 方法,它无法将其反序列化为 MyRequestModel
并且我收到此错误:
无法从 START_OBJECT 令牌中反序列化 java.lang.String
的实例
在 [来源:(PushbackInputStream); line: 3, column: 18] (通过引用链: MyRequestModel["queryResults"])]
【问题讨论】:
【参考方案1】:我想您问题的真正答案是:如果您需要将 queryResults
属性设为 String
,则实现自定义反序列化器。
如果不是,那么请使用 Jonatan 和 Montaser 在其他答案中提出的替代方案之一。
在 Spring Boot 中实现自定义反序列化器相当简单,因为 Jackson 是它的默认序列化器/反序列化器,它提供了一种编写我们自己的反序列化器的简单方法。
首先,创建一个实现StdDeserializer<T>
的类:
MyRequestModelDeserializer.java
public class MyRequestModelDeserializer extends StdDeserializer<MyRequestModel>
public MyRequestModelDeserializer()
this(null);
public MyRequestModelDeserializer(Class<?> vc)
super(vc);
@Override
public MyRequestModel deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException
JsonNode node = p.getCodec().readTree(p);
String userId = node.get("userId").asText();
String queryResults = node.get("queryResults").toString();
MyRequestModel model = new MyRequestModel();
model.setQueryResults(queryResults);
model.setUserId(userId);
return model;
其次,使用@JsonDeserialize
注解,使用您的自定义反序列化器将您的类标记为要反序列化:
MyRequestModel.java
@JsonDeserialize(using = MyRequestModelDeserializer.class)
public class MyRequestModel
private String userId;
private String queryResults;
完成了。
【讨论】:
谢谢。这看起来正是我需要的,但是由于某种原因,queryResults
的 json 对象被检索为空字符串。知道为什么上面从 JSON 节点读取 queryResults
的行会返回空字符串吗?
对我来说工作正常。能否请您给我看一下您的代码,以便我看看您的实现是否有问题?
你能详细说明上面的2个构造函数吗?我读了几篇文章,但没有解释它们的作用以及为什么需要它们。尤其是打了this(null)
的电话?另外,我将.asText()
更改为.toString()
,并且正要重新测试,看看是否可行。
。 . .我的错误,答案已编辑。在node.get("queryResults")
上使用toString()
来检索JSON。 asText()
不适用于 JSON 的对象类型字段。 . .现在,对于您的问题,Jackson 的ObjectMapper
在创建反序列化器实例时使用带有this(null)
的默认构造函数。 . .另一个构造函数——MyRequestModelDeserializer(Class<?> vc)
——你甚至可以省略它而只做public MyRequestModelDeserializer()this(MyRequestModel.class);
。此构造函数用于将处理的类设置为StdDeserializer
,以便您可以在运行时访问处理的类型。
谢谢,是的,我改用this(MyRequestModel.class)
并使用.asText()
作为userId(因为这不会添加两个额外的字符,它们是userId 周围的引号,所以我的数据库字段长度不会变成简称)和.toString()
以获取queryResults
CLOB 字符串值。非常感谢Matheus~【参考方案2】:
queryResults
在 Java 端是 String
,但在 JSON 端是 Object
。
如果您将其作为String
发送,您将能够对其进行反序列化:
"userId": "Dave",
"queryResults": "foo"
或者如果您创建映射到字段的类:
public class MyRequestModel
private String userId;
private QueryResults queryResults;
public class QueryResults
private String id;
private CarData carData;
private String carId;
private Integer status;
private String model;
或者如果你将它序列化为通用的东西(不推荐):
public class MyRequestModel
private String userId;
private Object queryResults;
public class MyRequestModel
private String userId;
private Map<String, Object> queryResults;
public class MyRequestModel
private String userId;
private JsonNode queryResults;
【讨论】:
非常感谢乔纳坦。我想我可能会考虑在下一次迭代中这样做,但现在,要求是使用 CLOB 将该值作为 CLOB 存储到 DB 中。 据我记得,如果你在JsonNode
上调用toString()
,你会得到你需要的东西(见我的最后一个例子)。在这种情况下,您不需要自定义逻辑来反序列化请求,它会更具可读性和灵活性。只需在创建推送到数据库的对象时执行String.valueOf(request.getQueryResults())
。【参考方案3】:
你有两个选项来反序列化这个请求:-
-
将
queryResults
的类型更改为Map<String, Object>
,它将接受所有作为key
和value
的对象。 (不推荐)
public class MyRequestModel
private String userId;
private Map<String, Object> queryResults;
-
您必须创建一个将
queryResults
的结果包装为对象的类。
class QueryResult
private String id;
private Map<String, Object> carData;
private String carId;
private Integer status;
private String model;
public QueryResult()
public QueryResult(String id, Map<String, Object> carData, String carId, Integer status, String model)
this.id = id;
this.carData = carData;
this.carId = carId;
this.status = status;
this.model = model;
public String getId()
return id;
public void setId(String id)
this.id = id;
public Map<String, Object> getCarData()
return carData;
public void setCarData(Map<String, Object> carData)
this.carData = carData;
public String getCarId()
return carId;
public void setCarId(String carId)
this.carId = carId;
public Integer getStatus()
return status;
public void setStatus(Integer status)
this.status = status;
public String getModel()
return model;
public void setModel(String model)
this.model = model;
并使queryResult
的类型如图所示:-
public class MyRequestModel
private String userId;
private QueryResult queryResults;
【讨论】:
非常感谢蒙塔泽。现在,我将不得不坚持使用 String,因为这是要求,但这可能会改变。所以,现在我必须将它作为 CLOB 存储到 DB 中,所以它必须是字符串。以上是关于Spring Boot JSON 没有反序列化到我的请求模型中的主要内容,如果未能解决你的问题,请参考以下文章
使用spring boot将JSON反序列化为带有通用对象列表的POJO
Spring Boot REST 服务:JSON 反序列化不起作用