GSON的使用(二)

2020-05-25  本文已影响0人  leilifengxingmw

本篇文章验证一些自己在开发过程中遇到的疑问

比如说我定义了一个Java数据类如下所示:

public class Category {

    private String contentType;
    private String coverPath;
    private int id;
    private String title;
    //注释1处,url默认值不为空
    private String url = "http://baidu.com";
    //省略getter/setter
}

注释1处,url默认是有值的,也就是说我们在使用的时候可以不判空。

疑问1

如果json字符串中没有url这个字段,那么在反序列化的时候,model的url字段是否为null?

{
  "contentType": "music",
  "coverPath": "http://xxx.png",
  "id": 99,
  "title": "音乐让我自由",
}

测试结果:Category类的url字段保持默认值不变。

疑问2

如果json字符串中有url这个字段,那么在串反序列化的时候,model的url字段是否为null?

{
  "contentType": "music",
  "coverPath": "http://xxx.png",
  "id": 99,
  "title": "音乐让我自由",
  "url": null
}

测试结果:Category类的url字段变为null。

疑问3

在反序列化过程中,如果我们发现json字符串中字段值为null

3.1 是否可以忽略这个字段呢,这样就可以不改变我们的默认值。

测试结果:目前没有看到这样的解决方法。

3.2 或者用一个默认值替代赋值给model类的字段?

测试结果:可以,自定义TypeAdapterFactoryTypeAdapter<T>

class StringAdapterFactory : TypeAdapterFactory {

    override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
        val rawType: Class<in T> = type.rawType

        if (rawType != String::class.java) {
            return null
        }
        //注释1处
        return StringAdapter() as (TypeAdapter<T>)
    }

    /**
     * Desc: 在将json字符串反序列化为model类的时候,如果String字段为null,
     * 那么就用空字符串("")替换,然后将空字符串("")赋值给model类的字段
     */
    class StringAdapter : TypeAdapter<String>() {

        override fun write(out: JsonWriter, value: String?) {
            out.value(value)
        }

        override fun read(reader: JsonReader): String {
            //注释2处
            if (reader.peek() == JsonToken.NULL) {
                reader.nextNull()
                return ""
            }
            return reader.nextString()
        }
    }
}

注释1处,如果在反序列化过程中字段类型是String,就使用自定义的StringAdapter。

注释2处,如果String字段为null,那么就用空字符串""替换,然后将空字符串""赋值给model类的字段。

使用

private fun createGson(): Gson {
    val gson = GsonBuilder()
          .registerTypeAdapterFactory(StringAdapterFactory())
          .create()
    return gson
}

构建Gson实例的时候,使用GsonBuilder来构建并注册StringAdapterFactory即可。

疑问4

Gson在反序列化的过程中对model类的构造函数是否有要求。

比如Category类,现在我们添加了一个无参构造函数(如果不手动添加,编译器会帮我们默认添加无参构造函数)。这时候反序列化是没有问题的。在反序列化过程中,会调用这个无参构造函数。

public class Category {

    private String contentType;
    private String coverPath;
    private int id;
    private String title;
    //注释1处,url默认值不为空
    private String url = "http://baidu.com";
    
    //无参构造函数
    public Category() {
        Log.d(TAG, "Category: construct");
    }
    
    //省略getter/setter
}

主动添加有参构造函数,这样编译器也不会给我们添加无参构造函数了。

public class Category {

    private static final String TAG = "Category";
    private String contentType;
    private String coverPath;
    private int id;
    private String title;
    private String url = "http://baidu.com";

    public Category(String contentType, String coverPath, int id, String title, String url) {
        Log.d(TAG, "Category: construct");
        this.contentType = contentType;
        this.coverPath = coverPath;
        this.id = id;
        this.title = title;
        this.url = url;
    }
    //...
}    

反序列化成功,但是不会调用这个构造函数。是使用sun.misc.Unsafe来创建实例的。细节可以参考这个链接 Is default no-args constructor mandatory for Gson?

疑问5

反序列化过程中匹配多个字段名的问题

public class UserSimple {

    @SerializedName(value = "name", alternate = {"fullName"})
    String name;
    String email;
    int age;
    boolean isDeveloper;
}

我们定义了UserSimple类,在反序列化过程中,name字段可以匹配name或者fullName。那么,如果在json字符串中namefullName都有,那么最终model类的name字段的值是多少呢?验证一下:

json字符串中name字段在前,fullName字段在后

{
    "name": "Norman",
    "fullName": "Hello world",
    "email": "norman@futurestud.io",
    "age": 26,
    "isDeveloper": true
}

验证结果:UserSimple类的name字段结果是Hello world

json字符串中fullName字段在前,name字段在后

{
    "fullName": "Hello world",
    "name": "Norman",
    "email": "norman@futurestud.io",
    "age": 26,
    "isDeveloper": true
}

验证结果:UserSimple类的name字段结果是Norman

结论:当json字符串中有多个值可以匹配model类的字段,那么model类的字段的最终取值是json字符串中后出现的值。

参考链接:

上一篇下一篇

猜你喜欢

热点阅读