使用@JsonDeserialize注解,自定义反序列化规则


写在前面


正文

需求

由于第三方接口提供方,在给我返回JSON串数据的时候,把空的时间,按照”00000000"的内容返回了,如果直接序列化的话,会被直接转为计算机起始时间“1970-01-01”实在是坑,但是客户就是上帝,没有办法!

解决方案

找了很多的博客,参考其中一个,进行了定制化修改,初步想到两种处理方式。

  • 改造set方法,在涉及到相关的Date格式的字段,在set方法中添加判断。
  • 往上想一步,肯定在反序列化的时候,是存在自定义反序列化的。
0.ObjectMapper反序列化JSON对象

使用ObjectMapper来进行反序列化,同样可以采用JSON.parseObject()来进行,就不需要设置(yyyyMMdd)时间格式。

ObjectMapper objectMapper = new ObjectMapper();
//设置时间格式
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
objectMapper.setDateFormat(dateFormat);
response = objectMapper.readValue(result, VoucherResponseDto.class);
1. @JsonDeserialize的使用
@JsonProperty("DATE")
@JsonDeserialize(using = "DateDerializerCustom"private Date date;

本质上,这个注解,是在属性的setter方法上起作用,把Json串对应属性名的字符串值转换为该属性的值,该注解常用的参数就是using,也就是使用哪个反编译规则。

2. 自定义反编译类编写
/**
 * @Description 自定义日期的反序列化,如果接口返回的为”00000000“返回null
 * @Author Jungle
 * @DATE 2021/12/20
 **/
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反编译
 	@Override
    public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
    {
        if (p.hasToken(JsonToken.VALUE_STRING)) {
            return p.getText();
        }
        JsonToken t = p.getCurrentToken();
        // [databind#381]
        if (t == JsonToken.START_ARRAY) {
            return _deserializeFromArray(p, ctxt);
        }
        // need to gracefully handle byte[] data, as base64
        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);
            }
            // otherwise, try conversion using toString()...
            return ob.toString();
        }
        // allow coercions for other scalar types
        // 17-Jan-2018, tatu: Related to [databind#1853] avoid FIELD_NAME by ensuring it's
        //   "real" scalar
        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的上下文类。

小结

根据业务实现反编译的规则实际上是不难的,但是如果涉及到复杂的对象反编译,还是需要公司有统一规范去编写,不可能是你一个处理,我一个处理的松散编程(实际上,小公司同一个项目都是你一个我一个的用)


参考资料


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值