JSON转Java对象反序列化失败:空字符串字段处理求助
问题
定义如下Java类:
@Data @NoArgsConstructor @AllArgsConstructor public class MatchingResponse { @JsonProperty(value = "Code") private String code; @JsonProperty(value = "Msg") private String message; @JsonProperty(value = "Id") private int id; @JsonProperty(value = "Date") private String date; @JsonProperty(value = "ClientIin") private String clientIin; @JsonProperty(value = "Similarity") private String similarity; @JsonProperty(value = "VendorName") private String vendorName; }
尝试反序列化以下JSON:
{ "Code": "200", "Msg": "", "Id": 20148, "Date": "2023-08-01T15:21:13.9704572+06:00", "ClientIin": "888888888888", "Similarity": "0.007720462", "VendorName": "SomeName" }
使用Jackson的代码:
ObjectMapper mapper = new ObjectMapper(); mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); byte[] byteResponse = httpResponse.getEntity().getContent().readAllBytes(); MatchingResponse response = mapper.readValue(byteResponse, MatchingResponse.class);
出现反序列化异常:
Cannot construct instance of `MatchingResponse` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"Code":"200","Msg":"","Id":20148,"Date":"2023-08-01T15:18:03.883337+06:00","ClientIin":"888888888888","Similarity":"0.0738383234","VendorName":"SomeName"}') at [Source: (byte[])"{\"Code\":\"200\",\"Msg\":\"\",\"Id\":20147,\"Date\":\"2023-08-01T15:18:03.883337+06:00\",\"ClientIin\":\"830921301593\",\"Similarity\":\"0.0738383234\",\"VendorName\":\"VisionLabs\"}""; line: 1, column: 1]
改用Gson也报错:
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 2 path $
尝试过添加@JsonSetter处理空字符串、自定义类级反序列化器、自定义String类型空字符串反序列化器等方法,均未解决问题。需要解决该反序列化错误,正确处理JSON中的空字符串字段。
解决方案
1. 核心问题定位
从异常信息可以看出,你获取的HTTP响应字节数组实际是被双引号包裹的转义字符串,而非直接的JSON对象。比如异常里显示的Source内容:
(byte[])"{\"Code\":\"200\",\"Msg\":\"\",\"Id\":20147,...}"
这意味着服务端返回的不是纯JSON,而是把JSON作为字符串返回(外层多了双引号,内部JSON字符被转义)。这才是导致Jackson/Gson报错的根本原因,和Msg字段的空字符串无关。
2. 修复步骤
方式一:手动处理转义字符串
先将字节数组转为字符串,去除外层的双引号并反转义,再反序列化为目标类:
ObjectMapper mapper = new ObjectMapper(); byte[] byteResponse = httpResponse.getEntity().getContent().readAllBytes(); // 去除首尾双引号,反转义JSON字符 String jsonStr = new String(byteResponse).replaceAll("^\"|\"$", "").replace("\\\\", "\\"); MatchingResponse response = mapper.readValue(jsonStr, MatchingResponse.class);
方式二:利用Jackson嵌套解析
先把外层字符串解析出来,再将内部内容转成目标类:
ObjectMapper mapper = new ObjectMapper(); byte[] byteResponse = httpResponse.getEntity().getContent().readAllBytes(); // 先读取外层字符串,再解析内部JSON String wrappedJson = mapper.readValue(byteResponse, String.class); MatchingResponse response = mapper.readValue(wrappedJson, MatchingResponse.class);
3. 空字符串字段处理(可选)
如果后续需要将空字符串转为null,不需要启用ACCEPT_EMPTY_STRING_AS_NULL_OBJECT(该配置针对对象类型,不适用于String),可以通过以下两种方式处理:
局部字段配置
给目标字段添加注解:
@JsonProperty(value = "Msg") @JsonSetter(nulls = Nulls.AS_NULL) // 空字符串转null private String message;
全局配置
通过自定义反序列化器实现全局空字符串转null:
ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addDeserializer(String.class, new JsonDeserializer<String>() { @Override public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { String value = p.getValueAsString(); return value == null || value.isEmpty() ? null : value; } }); mapper.registerModule(module);
内容的提问来源于stack exchange,提问作者Issatay Tleuov
相关产品推荐
相关产品推荐

