zoukankan      html  css  js  c++  java
  • ProtoStuff无法反序列化Deprecated注解成员问题记录

    在开发过程中,遇到一个鬼畜的问题,在DO的某个成员上添加@Deprecated注解之后,通过ProtoStuff反序列化得到的DO中,这个成员一直为null;花了不少时间才定位这个问题,特此记录一下

    原文 ProtoStuff无法反序列化Deprecated注解成员问题记录

    I. 全程实录

    1. 环境相关

    原项目中使用protostuff作为POJO序列化工具,对应的版本为

    <dependency>
        <groupId>io.protostuff</groupId>
        <artifactId>protostuff-runtime</artifactId>
        <version>1.5.9</version>
    </dependency>
    <dependency>
        <groupId>io.protostuff</groupId>
        <artifactId>protostuff-core</artifactId>
        <version>1.5.9</version>
    </dependency>
    

    2. 场景复现

    写了一个简单的demo,我们在POJO中添加一个拥有删除注解的成员,然后查看下反序列化结果

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class BDO implements Serializable {
        private String a;
        @Deprecated
        private String b;
    }
    
    @Test
    public void testSer() {
        BDO b = new BDO("10", "20");
        Schema<BDO> schema = RuntimeSchema.getSchema(BDO.class);
    
        LinkedBuffer buffer = LinkedBuffer.allocate(512);
        final byte[] protostuff;
        try {
            protostuff = ProtostuffIOUtil.toByteArray(b, schema, buffer);
        } finally {
            buffer.clear();
        }
    
        // deser
        BDO fooParsed = schema.newMessage();
        ProtostuffIOUtil.mergeFrom(protostuff, fooParsed, schema);
        System.out.println(fooParsed);
    }
    

    下面是测试输出,可以看到反序列化的结果中,b为null

    image

    自然就会有个疑问,是在序列化的时候直接丢掉了这个成员信息呢,还是反序列化的时候跳过了这个成员?

    我们新增一个POJO,与BDO的成员类似,只是没有@Deprecated注解

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class NDO implements Serializable {
        private String a;
        private String b;
    }
    

    然后验证下BDO序列化的结果,通过反序列化为NDO对象,如果b成员有值,说明在序列化的时候并没有丢掉;

    @Test
    public void testSer2() {
        BDO b = new BDO("10", "20");
        Schema<BDO> schema = RuntimeSchema.getSchema(BDO.class);
    
        LinkedBuffer buffer = LinkedBuffer.allocate(512);
        final byte[] protostuff;
        try {
            protostuff = ProtostuffIOUtil.toByteArray(b, schema, buffer);
        } finally {
            buffer.clear();
        }
    
        Schema<NDO> nSchema = RuntimeSchema.getSchema(NDO.class);
        NDO ndo = nSchema.newMessage();
        ProtostuffIOUtil.mergeFrom(protostuff, ndo, nSchema);
        System.out.println(ndo);
    }
    

    从下面的输出可以看到,反序列化不出来,在序列化的时候就已经丢掉了

    image

    接着我们再验证下NDO序列化的结果,因为没有Deprecated注解,反序列化为NDO对象时,应该是齐全的,那么反序列化为BDO呢

    @Test
    public void testSer3() {
        NDO n = new NDO("10", "20");
        Schema<NDO> schema = RuntimeSchema.getSchema(NDO.class);
    
        LinkedBuffer buffer = LinkedBuffer.allocate(512);
        final byte[] protostuff;
        try {
            protostuff = ProtostuffIOUtil.toByteArray(n, schema, buffer);
        } finally {
            buffer.clear();
        }
    
        NDO ans = schema.newMessage();
        ProtostuffIOUtil.mergeFrom(protostuff, ans, schema);
        System.out.println(ans);
    
        Schema<BDO> bSchema = RuntimeSchema.getSchema(BDO.class);
        BDO bdo = bSchema.newMessage();
        ProtostuffIOUtil.mergeFrom(protostuff, bdo, bSchema);
        System.out.println(bdo);
    }
    

    从下面的输出可以看出,反序列化时,成员上有@Deprecated注解时,也无法获取正确的结果

    image

    3. 兼容方案

    查了下protostuf的相关文档,个人感觉它的设计理念就是认为加了这个删除注解,就没有必要继续存在了,就直接给忽略了。那么我希望加上了这个注解的可以被序列化/反序列化,有办法么?

    查看api的时候,发现在创建Schema的时候,有个方法io.protostuff.runtime.RuntimeSchema#createFrom(java.lang.Class<T>, java.util.Map<java.lang.String,java.lang.String>, io.protostuff.runtime.IdStrategy), 可以指定成员列表

    于是我们就有了一个猥琐的兼容方式

    @Test
    public void testSer() {
        BDO b = new BDO("10", "20");
        Map<String, String> map = new HashMap<>();
        map.put("a", "a");
        map.put("b", "b");
        Schema<BDO> schema = RuntimeSchema.createFrom(BDO.class, map, RuntimeEnv.ID_STRATEGY);
        //        Schema<BDO> schema = RuntimeSchema.createFrom(BDO.class, new String[]{}, RuntimeEnv.ID_STRATEGY);
    
        LinkedBuffer buffer = LinkedBuffer.allocate(512);
        final byte[] protostuff;
        try {
            protostuff = ProtostuffIOUtil.toByteArray(b, schema, buffer);
        } finally {
            buffer.clear();
        }
    
        // deser
        BDO fooParsed = schema.newMessage();
        ProtostuffIOUtil.mergeFrom(protostuff, fooParsed, schema);
        System.out.println(fooParsed);
    }
    

    测试结果如下,反序列化的实例中有相应的数据了

    image

    4. 小结

    遵循ProtoStuff的使用规范,如果一个成员上有注解@Deprecated,那么这个成员的数据将不会被序列化和反序列化

    II. 其他

    1. 一灰灰Bloghttps://liuyueyi.github.io/hexblog

    一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

    2. 声明

    尽信书则不如,已上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

    3. 扫描关注

    一灰灰blog

    QrCode

    知识星球

    goals

  • 相关阅读:
    js 安全
    js压缩 uglify(2)
    js压缩 uglify
    抢红包算法 java
    手机调试
    Java中的随机数生成器:Random,ThreadLocalRandom,SecureRandom
    字符集编码 定长与变长
    db2 sqlcode
    2015.7.14(大盘结束红色,中色连坐4T)
    2015.7.10(全部涨停!想逢高出货,但是担心周一创新高)
  • 原文地址:https://www.cnblogs.com/yihuihui/p/11397129.html
Copyright © 2011-2022 走看看