写在前面
正文
需求
由于第三方接口提供方,在给我返回JSON串数据的时候,把空的时间,按照”00000000”的内容返回了,如果直接序列化的话,会被直接转为计算机起始时间“1970-01-01”实在是坑,但是客户就是上帝,没有办法!
解决方案
找了很多的博客,参考其中一个,进行了定制化修改,初步想到两种处理方式。
- 改造set方法,在涉及到相关的Date格式的字段,在set方法中添加判断。
- 往上想一步,肯定在反序列化的时候,是存在自定义反序列化的。
0.ObjectMapper反序列化JSON对象
使用ObjectMapper来进行反序列化,同样可以采用JSON.parseObject()来进行,就不需要设置(yyyyMMdd)时间格式。
1 2 3 4 5
| ObjectMapper objectMapper = new ObjectMapper();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); objectMapper.setDateFormat(dateFormat); response = objectMapper.readValue(result, VoucherResponseDto.class);
|
1. @JsonDeserialize的使用
1 2 3
| @JsonProperty("DATE") @JsonDeserialize(using = "DateDerializerCustom") private Date date;
|
本质上,这个注解,是在属性的setter方法上起作用,把Json串对应属性名的字符串值转换为该属性的值,该注解常用的参数就是using,也就是使用哪个反编译规则。
2. 自定义反编译类编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
public class DateDerializerCustom extends JsonDeserializer<Date> { @Override public Date deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { JsonToken currentToken = jp.getCurrentToken(); if (currentToken == JsonToken.VALUE_STRING) { return ctxt.readValue(jp, String.class).equals("00000000")?null:ctxt.readValue(jp, Date.class); } return null; } }
|
实际上,就是继承了JsonDeserilizer找个抽象类,重写反序列化的方法,可能直接看自定义的反编译类,有业务场景,不够通用,下面看一个底层Jackson自己实现的StringDerializer帮助理解;
3. StringDeserializer反编译
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| @Override public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { if (p.hasToken(JsonToken.VALUE_STRING)) { return p.getText(); } JsonToken t = p.getCurrentToken(); if (t == JsonToken.START_ARRAY) { return _deserializeFromArray(p, ctxt); } if (t == JsonToken.VALUE_EMBEDDED_OBJECT) { Object ob = p.getEmbeddedObject(); if (ob == null) { return null; } if (ob instanceof byte[]) { return ctxt.getBase64Variant().encode((byte[]) ob, false); } return ob.toString(); } if (t.isScalarValue()) { String text = p.getValueAsString(); if (text != null) { return text; } } return (String) ctxt.handleUnexpectedToken(_valueClass, p); }
|
可以看出,这里如果是个单字符串的值,其他的比如数组就会另外处理:”[],{}”。
相关参数说明:
JonParser:定义用于读取 JSON 内容的公共 API 的基类。 实例是使用JsonFactory实例的工厂方法创建(详情可阅读其源码,其包含很多的method)
DeserializationContext :JSON的上下文类。
小结
根据业务实现反编译的规则实际上是不难的,但是如果涉及到复杂的对象反编译,还是需要公司有统一规范去编写,不可能是你一个处理,我一个处理的松散编程(实际上,小公司同一个项目都是你一个我一个的用)
参考资料