1. 程式人生 > 程式設計 >ProtoStuff無法反序列化Deprecated註解成員問題記錄

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",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,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);
    System.out.println(fooParsed);
}
複製程式碼

測試結果如下,反序列化的例項中有相應的資料了

image

4. 小結

遵循ProtoStuff的使用規範,如果一個成員上有註解@Deprecated,那麼這個成員的資料將不會被序列化和反序列化

II. 其他

1. 一灰灰Blogliuyueyi.github.io/hexblog

一灰灰的個人部落格,記錄所有學習和工作中的博文,歡迎大家前去逛逛

2. 宣告

盡信書則不如,已上內容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發現bug或者有更好的建議,歡迎批評指正,不吝感激

3. 掃描關注

一灰灰blog

QrCode