GSON- GSON

时间:2020-01-09 10:36:11  来源:igfitidea点击:

GSON是Google的JSON解析器和Java生成器。 Google开发了GSON供内部使用,但后来将其开源。 GSON相当容易使用,但我认为它不如Hyman逊或者布恩(我认为获胜者)优雅。在本GSON教程中,我将指导我们如何使用GSON将JSON解析为Java对象,以及将Java对象序列化为JSON。

GSON包含多个可用于JSON的API。本教程介绍了" Gson"组件,该组件将JSON解析为Java对象,或者从Java对象生成JSON。除了Gson组件外,GSON在GSON JsonReader组件中还具有拉式解析器。

在使用GSON之前,必须首先在Java项目中安装GSON。我已经在有关GSON Installation的文章中对此进行了解释。

创建一个Gson实例

在使用GSON之前,必须首先创建一个新的Gson对象。有两种创建" Gson"实例的方法:

  • 使用new Gson()
  • 创建一个GsonBuilder实例并在其上调用create()。

这两种创建Gson实例的方式都将在本GSON教程中介绍。

新Gson()

我们可以简单地通过使用new Gson()指令创建对象来创建Gson对象。这是创建Gson对象的样子:

Gson gson = new Gson();

一旦创建了Gson实例,我们就可以开始使用它来解析和生成JSON。

GsonBuilder.build()

创建Gson实例的另一种方法是创建GsonBuilder()并调用其create()方法。这是创建GsonBuilder并调用create()的示例:

GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();

使用GsonBuilder允许我们在创建Gson对象之前在GsonBuilder上设置配置选项。我们将在本GSON教程的后面看到有关此示例。

将JSON解析为Java对象

GSON可以使用Gson对象的fromJson()方法将JSON插入Java对象。这是将JSON解析为Java对象的GSON示例:

String json = "{\"brand\":\"Jeep\", \"doors\": 3}";

Gson gson = new Gson();

Car car = gson.fromJson(json, Car.class);

该示例的第一行定义了要解析的JSON字符串。第二行创建一个" Gson"实例。第三行调用gson.fromJson()方法,该方法将JSON字符串解析为Car对象。

fromJson()的第一个参数是JSON来源。在上面的示例中,JSON源是一个字符串。 fromJson()方法的第二个参数是用于解析JSON到其实例的Java类。 " Gson"实例创建该类的实例,并将JSON解析为该类。因此,我们应确保此类具有无参数构造函数,否则GSON无法使用它。

这是Car类的外观:

public class Car {
    public String brand = null;
    public int    doors = 0;
}

从Java对象生成JSON

GSON还可以从Java对象生成JSON。我们可以通过" Gson"对象来实现。要生成JSON,我们可以调用Gson对象的toJson()方法。这是一个使用GSON从Java对象生成JSON的示例:

Car car = new Car();
car.brand = "Rover";
car.doors = 5;

Gson gson = new Gson();

String json = gson.toJson(car);

漂亮的印刷

默认情况下,由new Gson()创建的Gson实例以尽可能紧凑的JSON打印(生成)。这是默认Gson实例的紧凑型JSON输出示例:

{"brand":"Rover","doors":5}

但是,这种紧凑的JSON可能很难阅读。因此,GSON提供了一个漂亮的打印选项,可以其中打印JSON,以便在文本编辑器中更容易阅读。这是一个如何在启用漂亮打印的情况下创建Gson实例的示例:

Gson gson = new GsonBuilder().setPrettyPrinting().create();

这是打印相同的JSON的示例:

{
  "brand": "Rover",
  "doors": 5
}

排除字段

我们可以告诉GSON从序列中排除Java类中的字段。有几种告诉GSON排除字段的方法。 GSON教程的以下部分将介绍最有用和最容易使用的排除字段的方法。

临时字段

如果我们在Java类" transient"中创建一个字段,那么GSON将在序列化和反序列化中均将其忽略。这是前面的"汽车"类的外观,其中"品牌"字段标记为"Transient":

public class Car {
    public transient String brand = null;
    public int    doors = 0;
}

@Expose批注

GSON@ Expose批注(com.google.gson.annotations.Expose)可用于在对象序列化或者反序列化时将要公开或者不公开(包含或者不包含)的字段标记为。 @Expose注释可以带有两个参数。每个参数都是一个布尔值,可以取值true或者false。这是一些GSON@ Expose注释示例,以显示我的意思:

@Expose(serialize = true);
@Expose(serialize = false);
@Expose(deserialize = true);
@Expose(deserialize = false);
@Expose(serialize = true , deserialize = false);
@Expose(serialize = false, deserialize = true);

@Expose批注的serialize参数指定在序列化拥有对象时是否应包含带有@Expose批注的字段。 " deserialize"参数指定在对拥有的对象进行反序列化时是否应读取该字段。

这是一个使用GSON@ Expose注释的示例类:

public class Car {

    @Expose(serialize = false, deserialize = false)
    public String brand = null;

    @Expose(serialize = true, deserialize = true)
    public int    doors = 0;
}

注意字段上方的@Expose批注,告诉我们序列化或者反序列化时是否应包含给定的字段。

为了使GSON对@Expose批注做出反应,我们必须使用GsonBuilder类创建一个Gson实例。看起来是这样的:

GsonBuilder builder = new GsonBuilder();
builder.excludeFieldsWithoutExposeAnnotation();
Gson gson = builder.create();

注意,这种配置使GSON忽略了所有没有@ Expose注释的字段。要在序列化或者反序列化中包含一个字段,它上面必须有一个@Expose批注。

GsonBuilder.setExclusionStrategies()

在GSON中从序列化或者反序列化中排除类字段的另一种方法是在GsonBuilder上设置ExclusionStrategy,并使用GsonBuilder来构建Gson对象。

ExclusionStrategy是一个接口,因此我们必须创建一个实现ExclusionStrategy接口的类。这是一个使用匿名类实现ExclusionStrategy接口的示例:

ExclusionStrategy exclusionStrategy = new ExclusionStrategy() {
    public boolean shouldSkipField(FieldAttributes fieldAttributes) {
        if("brand".equals(fieldAttributes.getName())){
            return true;
        }
        return false;
    }

    public boolean shouldSkipClass(Class<?> aClass) {
        return false;
    }
};

注意,在示例ExclusionStrategy实现的shouldSkipField()方法内部,该示例检查给定的字段名称是否为brand。如果是,则将该字段排除在序列化和反序列化之外。

要使用ExclusionStrategy实现,请创建一个GsonBuilder,并使用setExclusionStrategies()方法在其上设置ExclusionStrategy,如下所示:

GsonBuilder builder = new GsonBuilder();
builder.setExclusionStrategies(exclusionStrategy);

Gson gson = builder.create();

" exclusionStrategy"变量必须指向" ExclusionStrategy"接口的实现。

序列化空字段

默认情况下," Gson"对象不会将具有" null"值的字段序列化为JSON。如果Java对象中的字段为null,则Gson会将其排除。

我们可以通过GsonBuilder强制Gson序列化null值。这是一个示例,显示了如何使用GSON强制对null值进行序列化:

GsonBuilder builder = new GsonBuilder();

builder.serializeNulls();

Gson gson = builder.create();

Car car = new Car();
car.brand = null;

String json = gson.toJson(car);
System.out.println(json);

请注意,在创建Gson对象之前,先在GsonBuilder实例上调用serializeNulls()。一旦调用了" serializeNulls()",则由" GsonBuilder"创建的" Gson"实例将在序列化的JSON中包含" null"字段。

上面示例的输出为:

{"brand":null,"doors":0}

注意" brand"字段如何为空。

GSON中的自定义实例创建者

默认情况下,GSON将尝试通过调用该类的no-arg构造函数来创建该类的实例。但是,如果给定的类没有默认的构造函数,或者我们想要对实例进行一些默认配置,或者想要创建子类的实例,则需要创建并注册自己的实例创建者。

GSON实例创建者只是一个对象工厂。实例创建者必须实现InstanceCreator接口(com.google.gson.InstanceCreator)。这是一个InstanceCreator实现的例子:

import com.google.gson.InstanceCreator;

public class CarCreator implements InstanceCreator<Car> {
    public Car createInstance(Type type) {
        Car car = new Car();
        car.brand = "Toyota";
        return car;
    }
}

在创建Gson实例之前,可以通过在GsonBuilder上注册上述CarCreator类来使用它。这是一个例子:

GsonBuilder gsonBuilder = new GsonBuilder();

gsonBuilder.registerTypeAdapter(Car.class, new CarCreator());

Gson gson  = gsonBuilder.create();

现在," Gson"实例将使用" CarCreator"实例创建" Car"实例。我们可以通过运行以下代码(在注册" CarCreator"之后)向自己证明:

String carJson = "{ \"doors\" : 4 }";

Car car = gson.fromJson(carJson, Car.class);

System.out.println(car.brand);

默认的brand属性值为null,并且JSON字符串不包含brand属性。因此,我们将看到在CarCreator的createInstance()方法(Toyota)内设置的brand属性的值。

GSON中的版本支持

GSON包含对其读取和写入的Java对象的简单版本支持。 GSON版本支持意味着我们可以用版本号标记Java类中的字段,然后让GSON根据它们的版本号在Java类中包括或者排除字段。

要使用GSON版本支持,我们必须首先使用GSON@ Since注释对Java类进行注释。这是一个示例" Person"类,其字段带有" @Since"注释:

import com.google.gson.annotations.Since;

public class Person {

    @Since(1.0)
    public String firstName = null;

    @Since(1.0)
    public String lastName = null;

    @Since(2.0)
    public String middleName = null;

    @Since(3.0)
    public String email = null;
}

其次,我们必须创建一个GsonBuilder并告诉它应该序列化到哪个版本以及从中反序列化。这是一个如何创建GsonBuilder并在其上设置版本号的示例:

GsonBuilder builder = new GsonBuilder();
builder.setVersion(2.0);

Gson gson = builder.create();

由上述GsonBuilder创建的Gson实例现在将仅包含以@Since(2.0)或者低于2.0的版本号注释的字段。在上面的"人"示例类中,这意味着字段"名字","姓氏"和"中间名"。 " email"字段使用版本3.0进行了注释,该版本高于2.0,因此GSON将排除" email"字段。

这是将" Person"对象序列化为JSON并查看生成的JSON的示例:

Person person     = new Person();
person.firstName  = "John";
person.lastName   = "Doe";
person.middleName = "Blocks";
person.email      = "[email protected]";

GsonBuilder builder = new GsonBuilder();
builder.setVersion(2.0);

Gson gson = builder.create();

String personJson = gson.toJson(person);

System.out.println(personJson);

本示例将打印出以下JSON字符串:

{"firstName":"John","lastName":"Doe","middleName":"Blocks"}

请注意,GSON如何在生成的JSON中排除email字段。

排除基于版本的字段对于将JSON读入Java对象(反序列化)的工作原理相同。查看下面的JSON字符串,其中包含所有字段,包括email字段:

"{\"firstName\":\"John\",\"lastName\":\"Doe\",\"middleName\":\"Blocks\",\"email\":\"[email protected]\"}"

如果我们要使用上面的Gson对象来读取Person对象,那么即使JSON字符串中存在email字段也不会被读取。这是使用上述Gson实例读取Person对象的样子:

String personJson2  = "{\"firstName\":\"John\",\"lastName\":\"Doe\",\"middleName\":\"Blocks\",\"email\":\"[email protected]\"}";

Person personRead = gson.fromJson(personJson2, Person.class);

自定义序列化和反序列化

GSON为我们提供了插入客户串行器和解串器的可能性。自定义序列化程序可以将Java值转换为自定义JSON,而自定义反序列化程序可以再次将自定义JSON转换为Java值。

自定义序列化器

GSON中的自定义序列化程序必须实现JsonSerializer接口。 JsonSerializer界面如下所示:

public interface JsonSerializer<T> {
    public JsonElement serialize(T value, Type type,
        JsonSerializationContext jsonSerializationContext) {
    }
}

实现一个可以序列化布尔值的自定义序列化器,如下所示:

public class BooleanSerializer implements JsonSerializer<Boolean> {

  public JsonElement serialize(Boolean aBoolean, Type type,
    JsonSerializationContext jsonSerializationContext) {
    if(aBoolean){
       return new JsonPrimitive(1);
    }
      return new JsonPrimitive(0);
  }
}

注意如何在两个地方用Boolean类替换T型参数。

在" serialize()"方法内部,我们可以将值(此cas中的" Boolean")转换为需要" serialize()"方法返回的" JsonElement"。在上面的示例中,我们使用了一个JsonPrimitive,它也是一个JsonElement。如我们所见,布尔值" true"被转换为1,而" false"被转换为0,而不是JSON中通常使用的" true"和" false"。

注册此自定义序列化器的操作如下:

GsonBuilder builder = new GsonBuilder();

builder.registerTypeAdapter(Boolean.class, new BooleanSerializer()) ;

Gson gson = builder.create();

这是对" registerTypeAdapter()"的调用,它向GSON注册了客户序列化程序。

一旦注册,从GsonBuilder创建的Gson实例将使用自定义序列化器。为了了解其工作原理,我们将使用以下POJO类:

public class PojoWithBoolean {

    public String username = null;
    public Boolean isSuperUser = false;
}

这是序列化PojoWithBoolean实例的样子:

PojoWithBoolean pojo = new PojoWithBoolean();
pojo.username = "abc";
pojo.isSuperUser = false;

String pojoJson = gson.toJson(pojo);

System.out.println(pojoJson);

从此示例打印的输出将是:

{"username":"abc","isSuperUser":0}

注意,isSuperUser的false值如何转换为0。

自定义反序列化器

GSON还为自定义解串器提供支持。自定义解串器必须实现JsonDeserializer接口。 JsonDeserializer界面如下所示:

public interface JsonDeserializer<T> {
    
    public Boolean deserialize(JsonElement jsonElement, 
        Type type, JsonDeserializationContext jsonDeserializationContext) 
        throws JsonParseException;

}

为Boolean类型实现自定义反序列化器如下所示:

public class BooleanDeserializer implements JsonDeserializer<Boolean> {

    public Boolean deserialize(JsonElement jsonElement, Type type,
    JsonDeserializationContext jsonDeserializationContext)
    throws JsonParseException {

        return jsonElement.getAsInt() == 0 ? false : true;
    }
}

使用另一个版本的registerTypeConverter()方法向GSON注册自定义解串器。这是向GSON注册上述解串器的样子:

GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Boolean.class, new BooleanDeserializer());

Gson gson = builder.create();

这是使用创建的Gson实例解析JSON字符串的样子:

String jsonSource = "{\"username\":\"abc\",\"isSuperUser\":1}";

PojoWithBoolean pojo = gson.fromJson(jsonSource, PojoWithBoolean.class);

System.out.println(pojo.isSuperUser);

从此GSON定制反序列化器示例打印的输出为:

true

...,因为JSON字符串中的1将转换为布尔值true