IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android序列化(四) 之 Gson -> 正文阅读

[移动开发]Android序列化(四) 之 Gson

1 概述

Json(JavaScript Object Notation)是一种可读性和通用性都非常强的轻量级的数据交换格式,一开始是JavaScript中广泛使用,到了后面流传几乎所有语言都有相应的使用API,所以它已是行业公认的标准。与JavaScript等的动态类型语言一起使用时非常方便,只要将数据转换成字符串,便可以在函数之间轻松地传递字符串进行数据传递。但是在像C++、Java等的静态类型语言序列化数据时,Json的效率表现仅一般,而且还需要编写较多代码来访问数据和转化成类对象。

Gson是Google开发的一个用于生成和解析Json数据格式的Java开源库。它的特点是可将Java类对象序列化为其Json字符串,也可将Json字符串反序列化成等效的Java类对象。

2 Json数据结构

Object:表示对象,使用大括号{}包含的键值对结构,Key必须是String类型,value为任何基本类型或者数组。

Array:表示数组,使用中括号[]包含一或多组Object,组间用逗号分隔。

例如:

{
  "id": 1001,
  "name": "子云心",
  "phones": [
    {
      "number": "12345678910",
      "type": "MOBILE"
    },
    {
      "number": "0000-1234567",
      "type": "HOME"
    }
  ],
  "verified": true
}

3 Android中Json的使用

String jsonText = "{\"id\":1001,\"name\":\"子云心\",\"phones\":[{\"number\":\"12345678910\",\"type\":\"MOBILE\"},{\"number\":\"0000-1234567\",\"type\":\"HOME\"}],\"verified\":true}";

Student student = new Student();
try {
    JSONObject jsonObject = new JSONObject(jsonText);
    if (jsonObject.has("id")) {
        int id = jsonObject.getInt("id");
        student.setId(id);
    }
    if (jsonObject.has("name")) {
        String name = jsonObject.getString("name");
        student.setName(name);
    }
    if (jsonObject.has("verified")) {
        boolean verified = jsonObject.getBoolean("verified");
        student.setVerified(verified);
    }
    if (jsonObject.has("phones")) {
        List<Student.Phone> phones = new ArrayList<>();
        JSONArray jsonArray = jsonObject.getJSONArray("phones");
        for (int i = 0; i < jsonArray.length(); i++) {
            Student.Phone phone = new Student.Phone();
            JSONObject phoneJsonObject = jsonArray.getJSONObject(i);
            if (phoneJsonObject.has("number")) {
                String number = phoneJsonObject.getString("number");
                phone.setNumber(number);
            }
            if (phoneJsonObject.has("type")) {
                String type = phoneJsonObject.getString("type");
                phone.setType(type);
            }

            phones.add(phone);
        }
        student.setPhones(phones);
    }

} catch (JSONException e) {
    e.printStackTrace();
}
public class Student {
    private int id;
    private String name;
    private boolean verified;
    private List<Phone> phones;

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setVerified(boolean verified) {
        this.verified = verified;
    }
    public boolean isVerified() {
        return verified;
    }
    public List<Phone> getPhones() {
        return phones;
    }
    public void setPhones(List<Phone> phones) {
        this.phones = phones;
    }

    static class Phone {
        private String number;
        private String type;

        public String getNumber() {
            return number;
        }
        public void setNumber(String number) {
            this.number = number;
        }
        public String getType() {
            return type;
        }
        public void setType(String type) {
            this.type = type;
        }
    }
}

4 使用Gson

4.1 依赖

Gson库地址:https://github.com/google/gson/,代码中使用需要先进行库的远程依赖:

dependencies {
    implementation 'com.google.code.gson:gson:2.8.8'
}

4.2 fromJson和toJson

继续使用上方Student示例,用Gson的代码是这样:

String jsonText = "{\"id\":1001,\"name\":\"子云心\",\"phones\":[{\"number\":\"12345678910\",\"type\":\"MOBILE\"},{\"number\":\"0000-1234567\",\"type\":\"HOME\"}],\"verified\":true}";

Gson gson = new Gson();
Student student = gson.fromJson(jsonText, Student.class);

String jsonText2 =gson.toJson(student);

Gson类提供了关键方式 fromJson(String,Class<T>) 和 toJson(Object, Type) 进行Json转对象和对象转Json。

注意:一般类对象,toJson(Object, Type)的第二个参数是可以忽略,但是如果需要序列化的对象是一个泛型对象或者集合类型对象,则一定要传入Type。例如:

Type shapeType = new TypeToken<Student>() {}.getType();
String jsonText3 =gson.toJson(student, shapeType);

Type listType = new TypeToken<List<String>>() {}.getType();
String jsonText4 =gson.toJson(student, listType);

4.3 Gson对象创建

使用Gson就是需要实例化一个Gson类对象,如上述代码可以简单地使用new Gson();的方式进行默认配置的创建,也可以通过Gson类提供的建造者模式的创建方式,例如:

Gson gson = new Gson();
Gson gson2 = new GsonBuilder()
??????? .setPrettyPrinting()
??????? .serializeNulls()
??????? .setVersion(1.0)
??????? .setDateFormat("yyyy-MM-dd HH:mm:ss")
??????? .registerTypeAdapter(Student.class, new StudentAdapter())
??????? .excludeFieldsWithModifiers(Modifier.TRANSIENT).create();

setPrettyPrinting

用于设置转成Json字符串数据是带格式化的,即带空格缩进。

serializeNulls

当对象字段为null时默认转成Json时是忽略的,而serializeNulls用于设置当对象字段为null时,转成Json仍保留字段名,其值为null,如:"name": null。

setVersion

用于设置Json版本值,例如上述设置了1.0的值后,当遇到带类中 @Since(1.1)注解的字段时(1.1版本>1.0版本),转换成Json后会忽略该字段。

setDateFormat

用于设置转成Json时日期时间的格式。

registerTypeAdapte

注册自定义的适配器(下方细讲)。

excludeFieldsWithModifiers

类对象在转成Json时会默认忽略类中的静态字段,而如果希望保留可以像上述设置.excludeFieldsWithModifiers(Modifier.TRANSIENT)。

4.4 常用注解

4.4.1 @Since

结合GsonBuilder.setVersion方法一起使用。例如setVersion设置了1.0的值后,当遇到带类中 @Since(1.1)注解的字段时(1.1版本>1.0版本),转换成Json后会忽略该字段。

4.4.2 @SerializedName

用于给类中字段更名,例如

@SerializedName("fullName")
private String name;            // 支持更名后的fullName

@SerializedName(value = "name", alternate = "fullName")
private String name;            // 新旧字段名称一起支持

4.4.3 @Expose

用于序列化或反序列化时忽略字段,例如:

@Expose()
private String name; // 参与序列化/反序列化

@Expose(serialize = false, deserialize = false)
private String name; // 不参与序列化,也不参与反序列化

@Expose(serialize = false)
private String name; // 只参与反序列化

@Expose(deserialize = false)
private String name;  // 只参与序列化

忽略某个字段序列化/反序列化还可以直接使用transient关键字 例如:

String transient name; //不参与序列化/反序列化

4.5 树模型

Gson可以支持构建了一个JsonObject节点树。 这是一种灵活的方法,类似于XML的DOM解析器,使用上类似Java中Json的使用里面的 JSONObject的用法。

String jsonText = "{\"id\":1001,\"name\":\"子云心\",\"phones\":[{\"number\":\"12345678910\",\"type\":\"MOBILE\"},{\"number\":\"0000-1234567\",\"type\":\"HOME\"}],\"verified\":true}";
Student student = read(jsonText);
public Student read(String jsonText) {
    Student student = new Student();
    JsonElement rootNode = JsonParser.parseString(jsonText);
    if (!rootNode.isJsonObject()) {
        return student;
    }
    JsonObject jsonObject = rootNode.getAsJsonObject();
    if(jsonObject.has("id")) {
        int id = jsonObject.get("id").getAsInt();
        student.setId(id);
    }
    if(jsonObject.has("name")) {
        String name = jsonObject.get("name").getAsString();
        student.setName(name);
    }
    if (jsonObject.has("phones")) {
        List<Student.Phone> phones = new ArrayList<>();
        JsonArray jsonArray = jsonObject.getAsJsonArray("phones");
        for (int i = 0; i < jsonArray.size(); i++) {
            Student.Phone phone = new Student.Phone();
            JsonObject phoneJsonObject = jsonArray.get(i).getAsJsonObject();
            if (phoneJsonObject.has("number")) {
                String number = phoneJsonObject.get("number").getAsString();
                phone.setNumber(number);
            }
            if (phoneJsonObject.has("type")) {
                String type = phoneJsonObject.get("type").getAsString();
                phone.setType(type);
            }
            phones.add(phone);
        }
        student.setPhones(phones);
    }
    if (jsonObject.has("verified")) {
        boolean verified = jsonObject.get("verified").getAsBoolean();
        student.setVerified(verified);
    }
    return student;
}

4.6 数据流

GSON数据流的方式读取Json数据是最低开销,并且读/写速度是非常快的方法,它类似于用于XML的SAX解析器。

String jsonText = "{\"id\":1001,\"name\":\"子云心\",\"phones\":[{\"number\":\"12345678910\",\"type\":\"MOBILE\"},{\"number\":\"0000-1234567\",\"type\":\"HOME\"}],\"verified\":true}";

Student student = null;
try {
    student = read(jsonText);
} catch (IOException e) {
    e.printStackTrace();
}

try {
    String jsonText2 = write(student);
} catch (IOException e) {
    e.printStackTrace();
}
public Student read(String jsonText) throws IOException {
    JsonReader reader = new JsonReader(new StringReader(jsonText));
    Student student = new Student();
    String fieldName = null;
    reader.beginObject();
    while (reader.hasNext()) {
        JsonToken token = reader.peek();
        if (token.equals(JsonToken.NAME)) {
            fieldName = reader.nextName();
        }

        if ("id".equals(fieldName)) {
            token = reader.peek();
            if (token.equals(JsonToken.NUMBER)) {
                int id = reader.nextInt();
                student.setId(id);
            }
            continue;
        }
        if ("name".equals(fieldName)) {
            token = reader.peek();
            if (token.equals(JsonToken.STRING)) {
                String name = reader.nextString();
                student.setName(name);
            }
            continue;
        }
        if ("phones".equals(fieldName)) {
            List<Student.Phone> phones = null;
            token = reader.peek();
            if (token.equals(JsonToken.BEGIN_ARRAY)) {
                reader.beginArray();
                phones = new ArrayList();
            }
            Student.Phone phone = null;
            while (!token.equals(JsonToken.END_ARRAY)) {
                token = reader.peek();
                if (token.equals(JsonToken.BEGIN_OBJECT)) {
                    reader.beginObject();
                    phone = new Student.Phone();
                    continue;
                }
                if (token.equals(JsonToken.NAME)) {
                    fieldName = reader.nextName();
                    if ("number".equals(fieldName)) {
                        token = reader.peek();
                        if (token.equals(JsonToken.STRING)) {
                            String number = reader.nextString();
                            phone.setNumber(number);
                        }
                        continue;
                    }
                    if ("type".equals(fieldName)) {
                        token = reader.peek();
                        if (token.equals(JsonToken.STRING)) {
                            String type = reader.nextString();
                            phone.setType(type);
                        }
                        continue;
                    }
                }
                if (token.equals(JsonToken.END_OBJECT)) {
                    phones.add(phone);
                    reader.endObject();
                    continue;
                }
            }
            student.setPhones(phones);
            reader.endArray();
            continue;
        }
        if ("verified".equals(fieldName)) {
            token = reader.peek();
            if (token.equals(JsonToken.BOOLEAN)) {
                boolean verified = reader.nextBoolean();
                student.setVerified(verified);
            }
            continue;
        }
    }
    reader.endObject();
    return student;
}
public String write(Student student) throws IOException {
    StringWriter stringWriter = new StringWriter();
    JsonWriter writer = new JsonWriter(stringWriter);

    writer.beginObject();

    writer.name("id");
    writer.value(student.getId());
    writer.name("name");
    writer.value(student.getName());

    writer.name("phones");
    writer.beginArray();
    for (int i = 0; i < student.getPhones().size(); i++) {
        writer.beginObject();
        writer.name("number");
        writer.value(student.getPhones().get(i).getNumber());
        writer.name("type");
        writer.value(student.getPhones().get(i).getType());
        writer.endObject();
    }
    writer.endArray();

    writer.name("verified");
    writer.value(student.isVerified());

    writer.endObject();

    return stringWriter.toString();
}

4.7 自定义适配器进行解析

Gson提供了两种自定义解析的方法:继承TypeAdapter类 和 实现JsonSerializer/JsonDeserializer接口

4.7.1继承TypeAdapter类

通过继承TypeAdapter类并传递目标类型的对象来创建自定义适配器。 重写它的read和write方法分别执行自定义的反序列化和序列化。

String jsonText = "{\"id\":1001,\"name\":\"子云心\",\"phones\":[{\"number\":\"12345678910\",\"type\":\"MOBILE\"},{\"number\":\"0000-1234567\",\"type\":\"HOME\"}],\"verified\":true}";

Gson gson = new GsonBuilder()
        .registerTypeAdapter(Student.class, new StudentAdapter())
        .create();

Student student = gson.fromJson(jsonText, Student.class);
String jsonText2 =gson.toJson(student);
public class StudentAdapter extends TypeAdapter<Student> {
    @Override
    public Student read(JsonReader reader) throws IOException {
        Student student = new Student();

        String fieldName = null;
        reader.beginObject();
        // ……
        // 中间跟4.6数据流 中read方法代码一样
        reader.endObject();
        return student;
    }

    @Override
    public void write(JsonWriter writer, Student student) throws IOException {
        writer.beginObject();
        // ……
         // 中间跟4.6数据流 中write方法代码一样
        writer.endObject();
    }
}

4.7.2实现JsonSerializer/JsonDeserializer接口

实现JsonSerializer和JsonDeserializer接口,并重写它们对应的serialize和deserialize方法同样可以实现自定义反序列化和序列。而且JsonSerializer和JsonDeserializer接口是不必同时实现的,这种方式也增加了其灵活性,不过代价就是解析效率也会有所降低,因为JsonElement最终也是会转成JsonReader进行序列化和反序列化。

public class StudentDeserializer implements JsonDeserializer<Student> {
    @Override
    public Student deserialize(JsonElement rootNode, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        Student student = new Student();
        if (!rootNode.isJsonObject()) {
            return student;
        }
        JsonObject jsonObject = rootNode.getAsJsonObject();
        // ……
        // 中间跟4.5树模型 中read方法代码一样
        return student;
    }
}

public class StudentSerializer implements JsonSerializer<Student> {
    @Override
    public JsonElement serialize(Student student, Type typeOfSrc, JsonSerializationContext context) {
        try {
            StringWriter stringWriter = new StringWriter();
            JsonWriter writer = new JsonWriter(stringWriter);

            writer.beginObject();
            // ……
            // 中间跟4.6数据流 中write方法代码一样
            writer.endObject();

            String jsonText = stringWriter.toString();
            JsonElement rootNode = JsonParser.parseString(jsonText);
            return rootNode;

        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }
}
String jsonText = "{\"id\":1001,\"name\":\"子云心\",\"phones\":[{\"number\":\"12345678910\",\"type\":\"MOBILE\"},{\"number\":\"0000-1234567\",\"type\":\"HOME\"}],\"verified\":true}";

Gson gson = new GsonBuilder()
        .registerTypeAdapter(Student.class, new StudentDeserializer())
        .registerTypeAdapter(Student.class, new StudentSerializer())
        .create();

Student student = gson.fromJson(jsonText, Student.class);
String jsonText2 =gson.toJson(student);

5 原理

我们从上面自定义适配器进行解析中大概也能知道,Gson的原理其实关键就是TypeAdapter,也是类型适配,如何将Json转成一个类对象和将类对象再转Json。Gson中的TypeAdapter大至可分为3类,分别是:

  1. 用户自定义类型适配器 –- 通过registerTypeAdapter传入
  2. 基本平台类型的适配器 – String、Int、Boolean等
  3. 通用反射类型适配器 –- ReflectiveTypeAdapter

5.1 自定义类型适配器

我们通过registerTypeAdapter方法传入的TypeAdapter类或者传入的JsonSerializer/JsonDeserializer接口最后会被赋值给一个factories变量:

GsonBuilder.java

private final List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) {
  // ……
  if (typeAdapter instanceof JsonSerializer<?> || typeAdapter instanceof JsonDeserializer<?>) {
    TypeToken<?> typeToken = TypeToken.get(type);
    factories.add(TreeTypeAdapter.newFactoryWithMatchRawType(typeToken, typeAdapter));
  }
  if (typeAdapter instanceof TypeAdapter<?>) {
    factories.add(TypeAdapters.newFactory(TypeToken.get(type), (TypeAdapter)typeAdapter));
  }
  return this;
}

而factories列表最终在构造Gson对象时会被传入其构造函数中去:

public Gson create() {
  List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>(this.factories.size() + this.hierarchyFactories.size() + 3);
  factories.addAll(this.factories);
  Collections.reverse(factories);

  List<TypeAdapterFactory> hierarchyFactories = new ArrayList<TypeAdapterFactory>(this.hierarchyFactories);
  Collections.reverse(hierarchyFactories);
  factories.addAll(hierarchyFactories);

  addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, factories);

  return new Gson(excluder, fieldNamingPolicy, instanceCreators,
      serializeNulls, complexMapKeySerialization,
      generateNonExecutableJson, escapeHtmlChars, prettyPrinting, lenient,
      serializeSpecialFloatingPointValues, longSerializationPolicy,
      datePattern, dateStyle, timeStyle,
      this.factories, this.hierarchyFactories, factories);
}

5.2 Gson的构造函数

Gson类最多参数的构造函数中最后的factoriesToBeAdded便是刚才通过registerTypeAdapter传入的自定义适配器:

Gson.java

Gson(Excluder excluder, FieldNamingStrategy fieldNamingStrategy,
    Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls,
    boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
    boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues,
    LongSerializationPolicy longSerializationPolicy, String datePattern, int dateStyle,
    int timeStyle, List<TypeAdapterFactory> builderFactories,
    List<TypeAdapterFactory> builderHierarchyFactories,
    List<TypeAdapterFactory> factoriesToBeAdded) {
  // ……

  List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();

  // built-in type adapters that cannot be overridden
  factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
  factories.add(ObjectTypeAdapter.FACTORY);

  // the excluder must precede all adapters that handle user-defined types
  factories.add(excluder);

  // registerTypeAdapter方法中传入的自定义的解析器
  factories.addAll(factoriesToBeAdded);

  // 基本平台类型的类型适配器
  factories.add(TypeAdapters.STRING_FACTORY);
  factories.add(TypeAdapters.INTEGER_FACTORY);
  factories.add(TypeAdapters.BOOLEAN_FACTORY);
  factories.add(TypeAdapters.BYTE_FACTORY);
  factories.add(TypeAdapters.SHORT_FACTORY);
  TypeAdapter<Number> longAdapter = longAdapter(longSerializationPolicy);
  factories.add(TypeAdapters.newFactory(long.class, Long.class, longAdapter));
  factories.add(TypeAdapters.newFactory(double.class, Double.class, doubleAdapter(serializeSpecialFloatingPointValues)));
  factories.add(TypeAdapters.newFactory(float.class, Float.class, floatAdapter(serializeSpecialFloatingPointValues)));
  factories.add(TypeAdapters.NUMBER_FACTORY);
  factories.add(TypeAdapters.ATOMIC_INTEGER_FACTORY);
  factories.add(TypeAdapters.ATOMIC_BOOLEAN_FACTORY);
  factories.add(TypeAdapters.newFactory(AtomicLong.class, atomicLongAdapter(longAdapter)));
  factories.add(TypeAdapters.newFactory(AtomicLongArray.class, atomicLongArrayAdapter(longAdapter)));
  factories.add(TypeAdapters.ATOMIC_INTEGER_ARRAY_FACTORY);
  factories.add(TypeAdapters.CHARACTER_FACTORY);
  factories.add(TypeAdapters.STRING_BUILDER_FACTORY);
  factories.add(TypeAdapters.STRING_BUFFER_FACTORY);
  factories.add(TypeAdapters.newFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL));
  factories.add(TypeAdapters.newFactory(BigInteger.class, TypeAdapters.BIG_INTEGER));
  factories.add(TypeAdapters.URL_FACTORY);
  factories.add(TypeAdapters.URI_FACTORY);
  factories.add(TypeAdapters.UUID_FACTORY);
  factories.add(TypeAdapters.CURRENCY_FACTORY);
  factories.add(TypeAdapters.LOCALE_FACTORY);
  factories.add(TypeAdapters.INET_ADDRESS_FACTORY);
  factories.add(TypeAdapters.BIT_SET_FACTORY);
  factories.add(DateTypeAdapter.FACTORY);
  factories.add(TypeAdapters.CALENDAR_FACTORY);
  factories.add(TimeTypeAdapter.FACTORY);
  factories.add(SqlDateTypeAdapter.FACTORY);
  factories.add(TypeAdapters.TIMESTAMP_FACTORY);
  factories.add(ArrayTypeAdapter.FACTORY);
  factories.add(TypeAdapters.CLASS_FACTORY);

  // type adapters for composite and user-defined types
  factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
  factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
  this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor);
  factories.add(jsonAdapterFactory);
  factories.add(TypeAdapters.ENUM_FACTORY);
  // 在最后添加通用的ReflectiveTypeAdapter
  factories.add(new ReflectiveTypeAdapterFactory(constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));

  this.factories = Collections.unmodifiableList(factories);
}

变量factories是一个TypeAdapterFactory列表,它用于存储不同类型的TypeAdapter工厂。Gson中每一种基本类型都会对应一个TypeAdapter进行适配,而所有我们自定义的类型(即示例中的Student)会由我们自己定义的解析器factoriesToBeAdded或者通用反射解析器ReflectiveTypeAdapter来完成适配。

5.3 基本平台类型的适配器

在Gson构造函数中添加了很多基本平台类型的适配器,基本平台类型的适配器在TypeAdapter类中实现,其中字符串和整型的适配器,其源码如下:

TypeAdapter.java

public static final TypeAdapterFactory STRING_FACTORY = newFactory(String.class, STRING);
public static final TypeAdapter<String> STRING = new TypeAdapter<String>() {
  @Override
  public String read(JsonReader in) throws IOException {
    JsonToken peek = in.peek();
    if (peek == JsonToken.NULL) {
      in.nextNull();
      return null;
    }
    /* coerce booleans to strings for backwards compatibility */
    if (peek == JsonToken.BOOLEAN) {
      return Boolean.toString(in.nextBoolean());
    }
    return in.nextString();
  }
  @Override
  public void write(JsonWriter out, String value) throws IOException {
    out.value(value);
  }
};

public static final TypeAdapterFactory INTEGER_FACTORY = newFactory(int.class, Integer.class, INTEGER);
public static final TypeAdapter<Number> INTEGER = new TypeAdapter<Number>() {
  @Override
  public Number read(JsonReader in) throws IOException {
    if (in.peek() == JsonToken.NULL) {
      in.nextNull();
      return null;
    }
    try {
      return in.nextInt();
    } catch (NumberFormatException e) {
      throw new JsonSyntaxException(e);
    }
  }
  @Override
  public void write(JsonWriter out, Number value) throws IOException {
    out.value(value);
  }
};

5.4 通用反射类型适配器

通用反射类型适配器就是ReflectiveTypeAdapter。因为所有的TypeAdapter都是通过TypeAdapterFactory的create方法进行创建,我们来看看ReflectiveTypeAdapter的create方法:

ReflectiveTypeAdapterFactory.java

@Override public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
  Class<? super T> raw = type.getRawType();
  if (!Object.class.isAssignableFrom(raw)) {
    return null; // it's a primitive!
  }
  ObjectConstructor<T> constructor = constructorConstructor.get(type);
  return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
}

方法返回一个Adapter类,Adapter类是ReflectiveTypeAdapterFactory的一个内部类,它继承于TypeAdapter,实现了read和write方法:

public static final class Adapter<T> extends TypeAdapter<T> {
  private final ObjectConstructor<T> constructor;
  private final Map<String, BoundField> boundFields;
  // 构造函数接收对象类型构造器和类型内部的所有字段列表
  Adapter(ObjectConstructor<T> constructor, Map<String, BoundField> boundFields) {
    this.constructor = constructor;
    this.boundFields = boundFields;
  }

  @Override public T read(JsonReader in) throws IOException {
    if (in.peek() == JsonToken.NULL) {
      in.nextNull();
      return null;
    }
    // 构造返回的类型对象
    T instance = constructor.construct();
    try {
      in.beginObject();
      while (in.hasNext()) {
        String name = in.nextName();
// 获取对象的字段BoundField对象
        BoundField field = boundFields.get(name);
        if (field == null || !field.deserialized) {
          in.skipValue();
        } else {
// 调用其read方法进行字段赋值
          field.read(in, instance);
        }
      }
    } catch (IllegalStateException e) {
      throw new JsonSyntaxException(e);
    } catch (IllegalAccessException e) {
      throw new AssertionError(e);
    }
    in.endObject();
    return instance;
  }

  @Override public void write(JsonWriter out, T value) throws IOException {
    if (value == null) {
      out.nullValue();
      return;
    }

    out.beginObject();
    try {
      for (BoundField boundField : boundFields.values()) {
        if (boundField.writeField(value)) {
          out.name(boundField.name);
          boundField.write(out, value);
        }
      }
    } catch (IllegalAccessException e) {
      throw new AssertionError(e);
    }
    out.endObject();
  }
}

Adapter类的构造函数接收两个参数,constructor是类的类型构造器,它是构造Gson时的第3个参数,boundFields是类型内部的所有字段列表,它由getBoundFields方法获取:

private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) {
  Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
  // ……
  Type declaredType = type.getType();
  while (raw != Object.class) {
// 获取类中所有的字段并进行遍历
    Field[] fields = raw.getDeclaredFields();
    for (Field field : fields) {
      boolean serialize = excludeField(field, true);
      boolean deserialize = excludeField(field, false);
      if (!serialize && !deserialize) {
        continue;
      }
      accessor.makeAccessible(field);
      Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
// 获取该字段的所有名称,因为当使用了@SerializedName注解时会出现多个名称
      List<String> fieldNames = getFieldNames(field);
      BoundField previous = null;
      for (int i = 0, size = fieldNames.size(); i < size; ++i) {
        String name = fieldNames.get(i);
        if (i != 0) serialize = false; // only serialize the default name
// 通过createBoundField方法来创建BoundField对象
        BoundField boundField = createBoundField(context, field, name,
            TypeToken.get(fieldType), serialize, deserialize);
        BoundField replaced = result.put(name, boundField);
        if (previous == null) previous = replaced;
      }
      if (previous != null) {
        throw new IllegalArgumentException(declaredType
            + " declares multiple JSON fields named " + previous.name);
      }
    }
    type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
    raw = type.getRawType();
  }
  return result;
}
static abstract class BoundField {
  final String name;
  final boolean serialized;
  final boolean deserialized;

  protected BoundField(String name, boolean serialized, boolean deserialized) {
    this.name = name;
    this.serialized = serialized;
    this.deserialized = deserialized;
  }
  abstract boolean writeField(Object value) throws IOException, IllegalAccessException;
  abstract void write(JsonWriter writer, Object value) throws IOException, IllegalAccessException;
  abstract void read(JsonReader reader, Object value) throws IOException, IllegalAccessException;
}

在Adapter类中read方法调用的boundField.read和write方法调用的boundField.write的实现就是在createBoundField方法内:

private ReflectiveTypeAdapterFactory.BoundField createBoundField(
    final Gson context, final Field field, final String name,
    final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
  final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());
  // special casing primitives here saves ~5% on Android...
  JsonAdapter annotation = field.getAnnotation(JsonAdapter.class);
  TypeAdapter<?> mapped = null;
  if (annotation != null) {
    mapped = jsonAdapterFactory.getTypeAdapter(constructorConstructor, context, fieldType, annotation);
  }
  final boolean jsonAdapterPresent = mapped != null;
  if (mapped == null) mapped = context.getAdapter(fieldType);

  final TypeAdapter<?> typeAdapter = mapped;
  return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
    @SuppressWarnings({"unchecked", "rawtypes"}) // the type adapter and field type always agree
    @Override void write(JsonWriter writer, Object value)
        throws IOException, IllegalAccessException {
      Object fieldValue = field.get(value);
      TypeAdapter t = jsonAdapterPresent ? typeAdapter
          : new TypeAdapterRuntimeTypeWrapper(context, typeAdapter, fieldType.getType());
      t.write(writer, fieldValue);
    }
    @Override void read(JsonReader reader, Object value) throws IOException, IllegalAccessException {
  // 如果是基础平台类型,直接读取,如果是自定义的类则递归前面的流程
      Object fieldValue = typeAdapter.read(reader);
      if (fieldValue != null || !isPrimitive) {
  // 反射给Field赋值
        field.set(value, fieldValue);
      }
    }
    @Override public boolean writeField(Object value) throws IOException, IllegalAccessException {
      if (!serialized) return false;
      Object fieldValue = field.get(value);
      return fieldValue != value; // avoid recursion for example for Throwable.cause
    }
  };
}

5.5 使用fromJson

我们在使用Student student = gson.fromJson(jsonText, Student.class); 时,最后会调用到Gson类中的fromJson(JsonReader reader, Type typeOfT)方法:

Gson.java

public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
  Object object = fromJson(json, (Type) classOfT);
  return Primitives.wrap(classOfT).cast(object);
}
public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
  if (json == null) {
    return null;
  }
  StringReader reader = new StringReader(json);
  T target = (T) fromJson(reader, typeOfT);
  return target;
}
public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {
  JsonReader jsonReader = newJsonReader(json);
  T object = (T) fromJson(jsonReader, typeOfT);
  assertFullConsumption(object, jsonReader);
  return object;
}
public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
  boolean isEmpty = true;
  boolean oldLenient = reader.isLenient();
  reader.setLenient(true);
  try {
    reader.peek();
    isEmpty = false;
    TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT);
// 获取合适适配器
    TypeAdapter<T> typeAdapter = getAdapter(typeToken);
// 调用适配器的read方法进行反序列化
    T object = typeAdapter.read(reader);
    return object;
  } catch (EOFException e) {
     ……
  } finally {
    reader.setLenient(oldLenient);
  }
}

fromJson方法内关键代码是调用了getAdapter来获取合适的适配器:

public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
  ……
  try {
    FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
    threadCalls.put(type, call);
    // 遍历TypeAdapterFactory列表,并调用其create创建TypeAdapter
    for (TypeAdapterFactory factory : factories) {
      TypeAdapter<T> candidate = factory.create(this, type);
      if (candidate != null) {
        call.setDelegate(candidate);
        typeTokenCache.put(type, candidate);
        return candidate;
      }
    }
    throw new IllegalArgumentException("GSON (" + GsonBuildConfig.VERSION + ") cannot handle " + type);
  } finally {
    threadCalls.remove(type);
    ……
  }
}

方法内遍历了factories 列表,factories 便是在Gson的构造函数中有通过registerTypeAdapter传入的多个自定义类型适配器、基本平台类型适配器和通用反射类型适配器。再通过调用其create方法,返回非空便是最后合适的适配器。

6 总结

Gson是可以将Java类对象序列化成Json字符串和可将Json字符串反序列化成等效的Java类对象的一个Json解析增强库。内部可通过数据流的形式或者树模式的形式进行Json的解析。在解析过程中根据类型选择合适的类型适配器再结合反射的机制,使用了简短的代码 toJson 和 fromJson 进行序列化和反序列化。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-03-21 21:02:21  更:2022-03-21 21:04:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 18:35:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码