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",
"norman@futurestud.io",
26,
true
); Gson gson = new Gson();
String userJson = gson.toJson(userObject);

反序列化:

String userJson = "{'age':26,'email':'norman@futurestud.io','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", "norman@futurestud.io", true, 26);
String usersJson = gson.toJson(user);

输出:

{
"Name": "Norman",
"_ageOfDeveloper": 26,
"email_of_developer": "norman@futurestud.io",
"isDeveloper": true
}

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

{
"name": "Norman",
"_age_of_developer": 26,
"email_of_developer": "norman@futurestud.io",
"is_developer": true
}

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

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

 {
"Name": "Norman",
"_AgeOfDeveloper": 26,
"Email_of_developer": "norman@futurestud.io",
"IsDeveloper": true
}

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

{
"Name": "Norman",
"_Age Of Developer": 26,
"Email_of_developer": "norman@futurestud.io",
"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", "norman@futurestud.io", 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", "norman@futurestud.io", 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", "norman@fs.io", 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": "norman@fs.io",
"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": "norman@fs.io",
"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": "norman@futurestud.io",
"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": "norman@fs.io",
"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", "norman@fs.io", 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
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

Gson - 学习的更多相关文章

  1. Json与Java对象互转之Gson学习

    Json与Java对象互转之Gson学习 请尊重他人的劳动成果.转载请注明出处:Json与Java对象互转之Gson学习         我曾在<XML,Object,Json转换之浅析Xstr ...

  2. Gson学习文档

    Gson:学习系列 http://www.codeceo.com/article/java-json-api-gson-1.html

  3. GSON学习笔记之初识GSON

    引用"JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,採用全然独立于语言的文本格式.为Web应用开发提供了一种理想的数据交换格式. " ...

  4. 原生态的ajax 及json和gson学习资源

    @RequestMapping(value = "/{id}/view") @jsobody public String viewProject( @PathVariable(&q ...

  5. gson学习以及进阶文章推荐

    Json转换利器Gson之实例一-简单对象转化和带泛型的List转化 (http://blog.csdn.net/lk_blog/article/details/7685169)Json转换利器Gso ...

  6. Gson学习记录

    Gson是Google开发来用来序列化和反序列化json格式数据的java库,他最大的特点就是对复杂类型的支持度高,可以完美解决java泛型问题,这得益于他对泛型类型数据的特殊处理,他的缺点就是速度慢 ...

  7. 使用Gson解析json

    前边的博客说过将json解析成java的方法,使用的是 这几个jar包,但是在解析时层遇到一个问题,就是在将时间字符串转换为java的Timestamp对象时会抛出异常,这个问题一直放在哪里没有去解决 ...

  8. beta冲刺(7/7)

    目录 组员情况 组员1:胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:恺琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:何宇恒 组员11:刘一好 展示组内最新 ...

  9. beta冲刺(6/7)

    目录 组员情况 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:恺琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示组内最新成果 团队签入记 ...

随机推荐

  1. BZOJ.3495.[PA2010]Riddle(2-SAT 前缀优化建图)

    题目链接 每个城市要么建首都要么不建,考虑2-SAT 这样一个国家内城市两两连边是很显然的,但是边数为O(n^2) 每个国家中仅有一个建首都,考虑新建前缀S[i]=1/0这2n个点表示当前国家的[1, ...

  2. CF 1131 E. String Multiplication

    E. String Multiplication 题意 分析: 从后往前考虑字符串变成什么样子. 设$S_i = p_1 \cdot p_2 \dots p_{i}$,最后一定是$S_{n - 1} ...

  3. Shiro笔记(一)基本概念

    Shiro笔记(一)基本概念 一.简介 Shiro是一个Java安全框架,可以帮助我们完成:认证.授权.加密.会话管理.与Web集成.缓存等. Authentication:身份认证/登录,验证用户是 ...

  4. If you sleep now,you will have a dream. If you study now,you will achieve your dream.

    If you sleep now,you will have a dream. If you study now,you will achieve your dream. 我开始思考,What's m ...

  5. Nginx 反向代理+高可用

    反向代理主机IP:10.0.0.20 WEB01主机IP : 10.0.0.22 WEB02主机IP : 10.0.0.23 反向代理主机配置:10.0.0.20 [root@node1 html]# ...

  6. zabbix 触发器

    概观 项目只收集数据.要自动评估传入数据,我们需要定义触发器.触发器包含一个表达式,该表达式定义数据的可接受级别的阈值. 如果这一级别超出了传入的数据,触发器将“ fire 触发”或进入“' Prob ...

  7. Spring Boot异常处理

    一.默认映射 我们在做Web应用的时候,请求处理过程中发生错误是非常常见的情况.Spring Boot提供了一个默认的映射:/error,当处理中抛出异常之后,会转到该请求中处理,并且该请求有一个全局 ...

  8. chapter15中使用generator来实现异步化操作的同步化表达的例子

    在p203中作者给了一个例子,我感觉这个例子写的不好,一开始我没有看懂,因为中间有很多细节没有交代,直到看了第二个用generator来实现ajax的例子之后才有所领悟.   所以我把作者给的这个用g ...

  9. 浅谈压缩感知(二十三):压缩感知重构算法之压缩采样匹配追踪(CoSaMP)

    主要内容: CoSaMP的算法流程 CoSaMP的MATLAB实现 一维信号的实验与结果 测量数M与重构成功概率关系的实验与结果 一.CoSaMP的算法流程 压缩采样匹配追踪(CompressiveS ...

  10. [Java] HashMap 源码简要分析

    特性 * 允许null作为key/value. * 不保证按照插入的顺序输出.使用hash构造的映射一般来讲是无序的. * 非线程安全. * 内部原理与Hashtable类似.   源码简要分析 pu ...