• Gson关于抽象类的序列化与反序列化


    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
    

      

  • 相关阅读:
    Git代码行数统计命令
    JPA访问数据库的几种方式
    爱码小士丨代码一敲十年,收入虽高前途摇摆
    “肉瘾”女孩从软件测试工程师到主管的成长感悟
    华为测试大牛Python+Django接口自动化怎么写的?
    携程大牛的单元测试是怎么样写的?
    Jmeter参数的AES加密使用
    弄啥嘞?热爱你的Bug
    “进腾讯工作一个月,我想辞职了”
    我在华为,软件测试人员在工作中如何运用Linux?
  • 原文地址:https://www.cnblogs.com/Gabby/p/10263389.html
Copyright © 2020-2023  润新知