Gson - 学习

Google 的 Gson 库,Gson 是一个非常强大的库,可以将 JSON 格式的数据转化成 Java 对象,也支持将 Java 对象转成 JSON 数据格式。

Gson 依赖

本文将会快速开始使用 Gson 进行序列化操作。由于很多读者都是 Android 开发人员,我们会提供 Java 环境中的 Gson。在开始之前,我们需要引入 Gson 库到自己的项目中,最新的版本是 2.8.0.

Gradle 项目添加

compile ‘com.google.code.gson:gson:2.8.0‘

Maven 项目添加

<dependencies>
    <dependency>
       <groupId>com.google.code.gson</groupId>
       <artifactId>gson</artifactId>
      <version>2.8.0</version>
       <scope>compile</scope>
    </dependency>
</dependencies>

基础

序列化:

UserSimple userObject = new UserSimple(
    "Norman",
    "[email protected]",
    26,
    true
);

Gson gson = new Gson();
String userJson = gson.toJson(userObject); 

反序列化:

String userJson = "{‘age‘:26,‘email‘:‘[email protected]‘,‘isDeveloper‘:true,‘name‘:‘Norman‘}";
Gson gson = new Gson();
UserSimple userObject = gson.fromJson(userJson, UserSimple.class);

数组反序列化:

public class Founder {
    String name;
    int flowerCount;
}
String founderJson = "[{‘name‘: ‘Christian‘,‘flowerCount‘: 1}, {‘name‘: ‘Marcus‘, ‘flowerCount‘: 3}, {‘name‘: ‘Norman‘, ‘flowerCount‘: 2}]";

Gson gson = new Gson();
Founder[] founderArray = gson.fromJson(founderJson, Founder[].class);

列表List反序列化:

String founderJson = "[{‘name‘: ‘Christian‘,‘flowerCount‘: 1}, {‘name‘: ‘Marcus‘, ‘flowerCount‘: 3}, {‘name‘: ‘Norman‘, ‘flowerCount‘: 2}]";

Gson gson = new Gson();

Type founderListType = new TypeToken<ArrayList<Founder>>(){}.getType();

List<Founder> founderList = gson.fromJson(founderJson, founderListType);

列表作为对象的一部分:反序列化时不需要传递 TypeToken

public class GeneralInfo {
    String name;
    String website;
    List<Founder> founders;
}

String generalInfoJson = "{‘name‘: ‘Future Studio Dev Team‘, ‘website‘: ‘https://futurestud.io‘, ‘founders‘: [{‘name‘: ‘Christian‘, ‘flowerCount‘: 1 }, {‘name‘: ‘Marcus‘,‘flowerCount‘: 3 }, {‘name‘: ‘Norman‘,‘flowerCount‘: 2 }]}";

Gson gson = new Gson();

GeneralInfo generalInfoObject = gson.fromJson(generalInfoJson, GeneralInfo.class);

Map反序列化:

public class AmountWithCurrency {
    String currency;
    int amount;
}

String dollarJson = "{ ‘1$‘: { ‘amount‘: 1, ‘currency‘: ‘Dollar‘}, ‘2$‘: { ‘amount‘: 2, ‘currency‘: ‘Dollar‘}, ‘3€‘: { ‘amount‘: 3, ‘currency‘: ‘Euro‘} }";

Gson gson = new Gson();

Type amountCurrencyType = new TypeToken<HashMap<String, AmountWithCurrency>>(){}.getType();

HashMap<String, AmountWithCurrency> amountCurrency =
gson.fromJson(dollarJson, amountCurrencyType);

Map 数据结构没有根元素,如 "[",我们就可以像解析 List 那用解析嵌套的 Map。

Set反序列化

String founderJson = "[{‘name‘: ‘Christian‘,‘flowerCount‘: 1}, {‘name‘: ‘Marcus‘, ‘flowerCount‘: 3}, {‘name‘: ‘Norman‘, ‘flowerCount‘: 2}]";

Gson gson = new Gson();

Type founderSetType = new TypeToken<HashSet<Founder>>(){}.getType();

HashSet<Founder> founderSet = gson.fromJson(founderJson, founderSetType);

泛型序列化:每种数据类型需要 new TypeToken 才能解析成功

Gson gson = new Gson();

List<Integer> integerList = new ArrayList<>();
integerList.add(1);
integerList.add(2);
integerList.add(3);

List<String> stringList = new ArrayList<>();
stringList.add("1");
stringList.add("2");
stringList.add("3");

Type integerType = new TypeToken<List<Integer>>() {}.getType();
Type stringType = new TypeToken<List<String>>() {}.getType();

String integerJson = gson.toJson(integerList, integerType);
String stringJson = gson.toJson(stringList, stringType);

@SerializedName

@SerializedName 是另一个非常实用的注解。@SerializedName 注解更改了自动匹配 JSON 字段的方式,平时开发中,我们总是默认保持 Java 类属性字段名和 JSON 的字段是一一对应,可有使用并不是总是这样的情况,也许你没有访问继承 Java 类或者你必须遵守公司的命名规则,这就需要使 @SerializedName 注解来匹配 Gson 字段,是一种非常优雅的方式。

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

SerializedName 接受两个参数,value、alternate。

SerializedName 改变了默认序列化和默认反序列化的字段取值,序列化时就是 value 的名称就是字段的名称,alternate 属性是用在反序列化上。

GsonBuider

public class UserNaming {
   String Name;
   String email_of_developer;
   boolean isDeveloper;
   int _ageOfDeveloper;
}

命名规则:

FieldNamingPolicy.IDENTITY:完全匹配我们 Java model 中的字段名,不管你有没有设置其他注解属性

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.IDENTITY);
Gson gson = gsonBuilder.create();

UserNaming user = new UserNaming("Norman", "[email protected]", true, 26);
String usersJson = gson.toJson(user);

输出:

{
    "Name": "Norman",
    "_ageOfDeveloper": 26,
    "email_of_developer": "[email protected]",
    "isDeveloper": true
}

FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES:将修改生成的 JSON 中的字段名,格式将全部变成小写,并且每个单词用“_” 分割

{
    "name": "Norman",
    "_age_of_developer": 26,
    "email_of_developer": "[email protected]",
    "is_developer": true
}

FieldNamingPolicy.LOWER_CASE_WITH_DASHES:每个单词用“-” 分隔

FieldNamingPolicy.UPPER_CAMEL_CASE:规则是每个单词的第一个字母都要大写,其他不变

 {
    "Name": "Norman",
    "_AgeOfDeveloper": 26,
    "Email_of_developer": "[email protected]",
     "IsDeveloper": true
}

FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES:每个单词的第一个字母会大写、每个单词使用空格分隔、含有 “_” 的链接的不会在使用空格

{
    "Name": "Norman",
    "_Age Of Developer": 26,
    "Email_of_developer": "[email protected]",
    "Is Developer": true
}

FieldNamingStrategy 自定义规则

FieldNamingStrategy customPolicy = new FieldNamingStrategy() {
    @Override
        public String translateName(Field f) {
            return f.getName().replace("_", "");
      }
};

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingStrategy(customPolicy);
Gson gson = gsonBuilder.create();

UserNaming user = new UserNaming("Norman", "[email protected]", true, 26);
String usersJson = gson.toJson(user);

序列化null

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.serializeNulls(); //重点
Gson gson = gsonBuilder.create();

UserSimple user = new UserSimple("Norman", null, 26, true);
String usersJson = gson.toJson(user);

输出:

{
      "age": 26,
      "email": null,
       "isDeveloper": true,
      "name": "Norman"
}

忽略策略

ExclusionStrategies 将 Date 和 boolean 类型的字段忽略、shouldSkipField 是用来忽略单个字段的,如果你想要忽略带有 “_” 的字段

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setExclusionStrategies(new ExclusionStrategy() {
    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return f.getName().contains("_");
    }

    @Override
    public boolean shouldSkipClass(Class<?> incomingClass) {
        return incomingClass == Date.class || incomingClass == boolean.class;
    }
});
Gson gson = gsonBuilder.create();

UserDate user = new UserDate("Norman", "[email protected]", 26, true);
String usersJson = gson.toJson(user);

上面的例子使用的是 setExclusionStrategies 方法,不管是序列化还是反序列化都会起作用,如果我们只想其中一个起作用,选择调下面的方法就行了:

  • addSerializationExclusionStrategy()
  • addDeserializationExclusionStrategy()

用法和 ExclusionStrategy 的实现一样,可重写两个方法实现。

基于 Modifiers 的忽略规则:

public class UserModifier {
    private String name;
    private transient String email;
    private static boolean isDeveloper;
    private final int age;
}

如果你想忽略 final 和 static 类型的字段, 保留 transient 类型的字段

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.excludeFieldsWithModifiers(Modifier.STATIC, Modifier.FINAL);
Gson gson = gsonBuilder.create();

UserModifier user = new UserModifier("Norman", "[email protected]", 26, true);
String usersJson = gson.toJson(user);

注解 @Expose

public class UserSimple {
        @Expose()
        String name; // equals serialize & deserialize

        @Expose(serialize = false, deserialize = false)
        String email; // equals neither serialize nor deserialize

        @Expose(serialize = false)
        int age; // equals only deserialize

        @Expose(deserialize = false)
        boolean isDeveloper; // equals only serialize
}

根据 @Expose 的用法,UserSimple 序列化 JSON 输出只有 name 和 isDeveloper,其他连个字段就不会被输出,因为 serialize 都是 false;

反序列化的话,只有 email 和 isDeveloper 被忽略,因为 deserialize = false

transient :使用 transient 来描述字段,将不能被序列化和反序列化

Lenient属性:

Gson 内部使用的是 JsonReader 类,看源码能发现里面有一个 lenient 的属性,默认是 false,也就是说默认值接受标准的 JSON 格式数据,如果数据有问题,将抛出异常解析失败。

JsonReader 也提供了设置 lenient 属性的方法,来忽略一些不标准的 JSON 数据格式。

特殊类型 Floats & Doubles

如果你 Java 对象中包含一个正常的 Floats 或者 Doubles 类型的数据,是可以正常序列化得到 JSON的,如果你传入 Float.POSITIVE_INFINITY 值,Gson 将会抛出异常,因为这个值是不能符合 JSON 标准的

解决的办法就是通过 GsonBuilder 设置 serializeSpecialFloatingPointValues() 方法

GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.serializeSpecialFloatingPointValues();
    Gson gson = gsonBuilder.create();
    UserFloat userFloat = new UserFloat("Norman", Float.POSITIVE_INFINITY);
    String usersJson = gson.toJson(userFloat);
    System.out.println("userJson:" + usersJson);

自定义序列化:

public class UserSubscription {
    String name;
    String email;
    int age;
    boolean isDeveloper;

    // new!
    List<Merchant> merchantList;
}

public class Merchant {
    private int Id;
    private String name;

    // possibly more properties
}
JsonSerializer<Merchant> serializer = new JsonSerializer<Merchant>() {
    @Override
    public JsonElement serialize(Merchant src, Type typeOfSrc, JsonSerializationContext context) {
        JsonObject jsonMerchant = new JsonObject();

        jsonMerchant.addProperty("Id", src.getId());

        return jsonMerchant;
    }
};

GsonBuilder gsonBuilder = new GsonBuilder();

gsonBuilder.registerTypeAdapter(Merchant.class, serializer);

Gson customGson = gsonBuilder.create();
String customJSON = customGson.toJson(subscription);

自定义序列化List:

JsonSerializer<List<Merchant>> serializer =
    new JsonSerializer<List<Merchant>>() {
        @Override
        public JsonElement serialize(List<Merchant> src, Type typeOfSrc, JsonSerializationContext context) {
            JsonObject jsonMerchant = new JsonObject();

            List<String> merchantIds = new ArrayList<>(src.size());
            for (Merchant merchant : src) {
                merchantIds.add("" + merchant.getId());
            }

            String merchantIdsAsString = TextUtils.join(",", merchantIds);

            jsonMerchant.addProperty("Ids", merchantIdsAsString);

            return jsonMerchant;
        }
}

GsonBuilder gsonBuilder = new GsonBuilder();

Type merchantListType = new TypeToken<List<Merchant>>() {}.getType();  

gsonBuilder.registerTypeAdapter(merchantListType, serializer);

Gson customGson = gsonBuilder.create();
String customJSON = customGson.toJson(subscription);

//结果
{
  "age": 26,
  "email": "[email protected]",
  "isDeveloper": true,
  "merchantList": {
    "Ids": "23,42"
  },
  "name": "Norman"
}

简化:

JsonSerializer<List<Merchant>> serializer =
    new JsonSerializer<List<Merchant>>() {
        @Override
        public JsonElement serialize(List<Merchant> src, Type typeOfSrc, JsonSerializationContext context) {
            JsonArray jsonMerchant = new JsonArray();

            for (Merchant merchant : src) {
                jsonMerchant.add("" + merchant.getId());
            }

            return jsonMerchant;
        }
}//结果
{
  "age": 26,
  "email": "[email protected]",
  "isDeveloper": true,
  "merchantList": [
    "23",
    "42"
  ],
  "name": "Norman"
}
 

自定义反序列化:

前三个表示年月日,是一个日期结构,后面四个字段表示一个 model 信息

//模型
public class UserDate {
    private String name;
    private String email;
    private boolean isDeveloper;
    private int age;
    private Date registerDate;
}

//Json
{
    "year": 116,
    "month": 5,
    "day": 21,
    "age": 26,
    "email": "[email protected]",
    "isDeveloper": true,
    "name": "Norman"
}
JsonDeserializer<UserDate> deserializer = new JsonDeserializer<UserDate>() {
    @Override
    public UserDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonObject jsonObject = json.getAsJsonObject();

        Date date = new Date(
                jsonObject.get("year").getAsInt(),
                jsonObject.get("month").getAsInt(),
                jsonObject.get("day").getAsInt()
        );

        return new UserDate(
                jsonObject.get("name").getAsString(),
                jsonObject.get("email").getAsString(),
                jsonObject.get("isDeveloper").getAsBoolean(),
                jsonObject.get("age").getAsInt(),
                date
        );
    }
};

GsonBuilder gsonBuilder = new GsonBuilder();

gsonBuilder.registerTypeAdapter(UserDate.class, deserializer);

Gson customGson = gsonBuilder.create();
UserDate customObject = customGson.fromJson(userJson, UserDate.class);

自定义对象示例创建:

//Json

 {
      "age": 26,
      "email": "[email protected]",
      "isDeveloper": true,
      "name": "Norman"
}

//Model
public class UserContext {
    private String name;
    private String email;
    private boolean isDeveloper;
    private int age;

    // additional attribute, which is not part of the data model
    private Context context; 

    public UserContext(Context context) {
        this.context = context;
    }
}

如果你还是用原来的方式来反序列化,那么得到的 Context 肯定是null。你需要在映射之前的构造函数中来创建 Context,这是就需要用到 InstanceCreators。

String userSimpleJson = ...; // the JSON from the server, see above

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(
    UserContext.class,
    new UserContextInstanceCreator(getApplicationContext())
);
Gson customGson = gsonBuilder.create();

UserContext customObject = customGson.fromJson(userSimpleJson, UserContext.class);

private class UserContextInstanceCreator implements InstanceCreator<UserContext> {
    private Context context;

    public UserContextInstanceCreator(Context context) {
        this.context = context;
    }

    @Override
    public UserContext createInstance(Type type) {
        // create new object with our additional property
        UserContext userContext = new UserContext(context);

        // return it to gson for further usage
        return userContext;
    }
}

@JsonAdapter 注解:

public class MerchantListSerializer implements JsonSerializer<List<Merchant>> {
    @Override
    public JsonElement serialize(List<Merchant> src, Type typeOfSrc, JsonSerializationContext context) {
        JsonArray jsonMerchant = new JsonArray();

        for (Merchant merchant : src) {
            jsonMerchant.add("" + merchant.getId());
        }

        return jsonMerchant;
    }
}

public class UserSubscriptionAnnotation {
    String name;
    String email;
    int age;
    boolean isDeveloper;

    // new!
    @JsonAdapter(MerchantListSerializer.class)
    List<Merchant> merchantList;
}

UserSubscriptionAnnotation subscription = new UserSubscriptionAnnotation( "Norman", "[email protected]", 26, true, subscribedMerchants);

Gson gson = new Gson();

String fullJSON = gson.toJson(subscription);

 

只有是类的形式,我们才能使用注解 @JsonAdapter 来添加 MerchantListSerializer。就像之前的一些注解用法一样,并添加到你需要序列化的 Java model 中。

可以看到 merchantList 被添加了 @JsonAdapter(MerchantListSerializer.class) 注解,而 MerchantListSerializer 正是我们序列化过程的实现类,这样我们就不用使用 GsonBuilder 它来创建的 Gson 对象,而是使用默认创建对象就可以,也不需要那些复杂的设置。

反序列化:和序列化不同的是,@JsonAdapter(UserDateDeserializer.class) 注解是要添加在类级别上面,这是一点不同。

转载自:
作者:無名小子的杂货铺
链接:https://www.jianshu.com/p/215708d00015
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

原文地址:https://www.cnblogs.com/icebutterfly/p/9547792.html

时间: 2024-10-12 23:37:42

Gson - 学习的相关文章

Json与Java对象互转之Gson学习

Json与Java对象互转之Gson学习 请尊重他人的劳动成果,转载请注明出处:Json与Java对象互转之Gson学习         我曾在<XML,Object,Json转换之浅析Xstream的使用>一文中介绍过使用XStream进行XML,Object,Json之间的转换,虽然XStream内置了对Json的支持,但是效果不是特别好,毕竟XStream重点不在Json.下面就介绍另外一种工具.           Gson(又称Google Gson)是Google公司发布的一个开放

GSON学习笔记之初识GSON

引用"JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,採用全然独立于语言的文本格式.为Web应用开发提供了一种理想的数据交换格式. " 曾经手机端与server数据交互的时候用过xml格式,后来又用了JSON格式,无论是server生成json数据,还是手机端解析json数据,尽管用到一些json库,但都比較繁琐.近期从一些项目中发现了Google的gson,就開始学习使用.经过比較,发现gson与其它json库最大的不同是.gson直接使用

gson学习以及进阶文章推荐

Json转换利器Gson之实例一-简单对象转化和带泛型的List转化 (http://blog.csdn.net/lk_blog/article/details/7685169)Json转换利器Gson之实例二-Gson注解和GsonBuilder (http://blog.csdn.net/lk_blog/article/details/7685190)Json转换利器Gson之实例三-Map处理(上) (http://blog.csdn.net/lk_blog/article/details

Retrofit2.0通俗易懂的学习姿势,Retrofit2.0 + OkHttp3 + Gson + RxJava

Retrofit2.0通俗易懂的学习姿势,Retrofit2.0 + OkHttp3 + Gson + RxJava Retrofit,因为其简单与出色的性能,也是受到很多人的青睐,但是他和以往的通信框架还是有点区别,不过放心,因为他本身还是挺简单的,所有我相信你看完这篇文章,对基本的请求是没什么问题的,其实现在网上这样的文章也有很多了,好了,那我们直接开车吧! 一.相关资料 Github:https://github.com/square/retrofit 官网文档:http://square

GSON使用的学习笔记,进阶篇(三)

本篇笔记内容比较杂乱,没有专门去整理. TypeAdapter 现在轮到TypeAdapter类上场,但考虑到gson默认行为已足够强大,加上项目实践中应用json时场景不会太复杂,所以一般不需要自定义TypeAdapter.TypeAdapter优点是集成了JsonWriter和JsonReader两个类,定义了一套与gson框架交互的良好接口,同时便于管理编码和解码的实现代码,不至于太零碎.因而在了解JsonReader和JsonWriter的使用方法之后,自定义TypeAdapter类来完

Gson的学习与使用

Gson介绍: GSON是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库.可以将一个Json字符转成一个Java对象,或者将一个Java转化为Json字符串. 特点: a.快速.高效 b.代码量少.简洁 c.面向对象 d.数据传递和解析方便 Gson的pom依赖: <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactI

GSON源码LinkedTreeMap学习

在学习GSON的过程中,发现了GSON的基础数据类型LinkedTreeMap,因此展开学习. private final LinkedTreeMap<String, JsonElement> members = new LinkedTreeMap<String, JsonElement>(); LinkedTreeMap,一切如此的熟悉,在jdk中有LinkedMap有TreeMap有TreeMap,这个LinkedTreeMap是个什么,顾名思义,这应该是一个连续的且有序的集合

Google中Gson的使用解析json数据-------学习篇

之前写过一篇Gson解析json数据的基本应用,这里不多说,直接上例子. 有兴趣的可以先阅读下之前那篇,这里附上链接: http://www.cnblogs.com/Ant-soldier/p/6322456.html // json跟set集合之间的转换        String str = "[{'name':'zhangsan','age':20},{'name':'lisi','age':33}]";        Gson gson = new Gson();      

JavaFX基础学习之OkHttp/Gson

导入jar包,使用OkHttp/Okio/Gson请求解析 package application; import java.io.IOException; import java.net.URL; import java.util.ResourceBundle; import com.google.gson.Gson; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializab