1. 程式人生 > >Gson關於抽象類的序列化與反序列化

Gson關於抽象類的序列化與反序列化

fin nco unknown lang eat toc sun 關於 我們

Gson關於抽象類的序列化與反序列化

背景知識

Gson是Google推出的Java對象與Json對象的之間轉換的Java類庫,需要將Java對象序列化時,使用

  A a = new A();  
   // Java對象序列化成String
  Gson gson = new Gson();  
  // String 反序列成Java對象   
  String jsonStr = gson.toJson(a);   
  A res = gson.fromJson(jsonStr, A.class);  

  

問題背景

我需要將一個Java對象轉成json對象進行持久化,在序列化工具中,我們知道gson是一個代碼量少,簡潔並且快速的Java類庫,由此我選擇了它進行序列化,但是其中發現一個問題:gson沒有辦法去將一個抽象類反序列化出來,並且在序列化的時候還不會報錯,下面直接上代碼: 首先給出我們需要序列化的類們: 抽象類:

public abstract class BaseBO implements Serializable {
    private String name;
    private Integer age;

}

  

baseBO的繼承類:

public class Person extends BaseBO {
    private Boolean sex;
    private String address;

}

  

測試類:

 public static void main(String[] args) {

        Gson gson = new Gson();
        BaseBO baseBO = new Person();
        baseBO.setName("emma");
        baseBO.setAge(100);
        String jsonString = gson.toJson(baseBO, BaseBO.class );
        BaseBO res = gson.fromJson(jsonString, BaseBO.class);
        System.out.println(res);
    }

  

運行後報錯,報錯信息如下:

Exception in thread "main" java.lang.RuntimeException: Failed to invoke public com.alibaba.test.BaseBO() with no args
    at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:111)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:210)
    at com.google.gson.Gson.fromJson(Gson.java:888)
    at com.google.gson.Gson.fromJson(Gson.java:853)
    at com.google.gson.Gson.fromJson(Gson.java:802)
    at com.google.gson.Gson.fromJson(Gson.java:774)
    at com.alibaba.test.TestApplication.main(TestApplication.java:17)
Caused by: java.lang.InstantiationException
    at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:48)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:108)
    ... 6 more

  

說明:從上面這段報錯信息可以看出,gson不能序列化一個抽象類,因為抽象類沒有辦法使用構造函數去構造出來,所以他沒辦法序列化,那我們如果需要對存在baseBO的類進行序列化呢?我們需要一個適配器,在序列化的時候將抽象類使用的繼承類的類名存下來,然後在反序列化的時候指定他的實現類,就像這樣:

public class BaseBoAdapter implements JsonSerializer<BaseBO>, JsonDeserializer<BaseBO> {

    @Override
    public BaseBO deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
        throws JsonParseException {
        JsonObject jsonObject = json.getAsJsonObject();
        String type = jsonObject.get("type").getAsString();
        JsonElement element = jsonObject.get("properties");

        try {
            // 指定包名+類名
            String thePackage = "org.test.";
            return context.deserialize(element, Class.forName(thePackage + type));
        } catch (ClassNotFoundException cnfe) {
            throw new JsonParseException("Unknown element type: " + type, cnfe);
        }
    }

    @Override
    public JsonElement serialize(BaseBO src, Type typeOfSrc, JsonSerializationContext context) {
        JsonObject result = new JsonObject();
        result.add("type", new JsonPrimitive(src.getClass().getSimpleName()));
        result.add("properties", context.serialize(src, src.getClass()));

        return result;
    }
}

  

需要實現JsonSerializerJsonDeserializer中的序列化和反序列的方法,然後在new Gson()的時候將這個適配器註冊進去,就像這樣:

Gson gson = new GsonBuilder()
            .registerTypeAdapter(BaseBO.class, new BaseBoAdapter())
            .create();

  

然後,你就可以得到正確的結果了,如下:

org.test.Person@62043840[name=emma,age=100]

Process finished with exit code 0

  

Gson關於抽象類的序列化與反序列化