GsonQuickStart

本文深入探讨Gson库的使用技巧,包括解析JsonObject、数组、复杂对象及自定义规则,详解GsonBuilder配置与注解应用,助你高效处理JSON数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Gson 快速开始!

Gson是谷歌搞出来的用来解析json的工具,运用了java的反射机制,他的功能主要有:

  1. 将java对象解析成json对象
  2. 将json对象解析成java对象

使用时需要在maven工程中导入相应依赖

<dependency>
   <groupId>com.google.code.gson</groupId>
   <artifactId>gson</artifactId>
   <version>2.1</version>
</dependency>
or
compile 'com.google.code.gson:gson:2.3.1'

解析

解析情况分为三种:

  1. 标量(Scalar),也就是单纯的字符串或则数字形式
  2. 序列(Sequence),也就是若干数据按照一定顺序并列在一起又称“数组”
  3. 映射(Mapping),也就是key/value键值对

JsonObject对象

将一个json串解析成一个JsonObject对象,对于获取其中一些简单的属性比较方便,免去了写映射类了

// json:{"tasks":[{"id":"123","name","pp"},{"id":"456","name","mm"}]}
JsonObject workInfoObj = gson.fromJson(workInfoObjStr,JsonObject.class);
String workTaskId = workInfoObj.get("tasks").getAsJsonArray().get(0).getAsJsonObject().get("id").getAsString();

JsonObject方法详情查看:https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/JsonObject.html

普通对象

采用映射方式,将JavaBean对象的属性值与json对象进行映射,注意:不匹配的属性不会被映射,字段值必须一样!

  String json_str = "{"name":"kalen", "age":22}";
  Gson gson = new Gson();
  User user = gson.fromGson(json_str, User.class);

数组对象

//数组对应gson中的类型
Type listType = new TypeToken<List<String>>() {}.getType();
//gson需要的转换对象或则数据来源
List<String> target = new LinkedList<String>();
target.add("blah");
Gson gson = new Gson();
// 将list对象转为json对象
String json = gson.toJson(target, listType);
// 将json对象转为list对象
List<String> target2 = gson.fromJson(json, listType);

此处使用了泛型

注意:当解析非基本数据类型和数组时,需要加上泛型!

Gson gson = new Gson();
String jsonArray = "[\"Android\",\"Java\",\"PHP\"]";
String[] strings = gson.fromJson(jsonArray, String[].class);

但对于List将上面的代码中的 String[].class 直接改为 List.class 是行不通的。对于Java来说ListList 这俩个的字节码文件只一个那就是List.class,这是Java泛型使用时要注意的问题 泛型擦除

为了解决的上面的问题,Gson为我们提供了TypeToken来实现对泛型的支持,所以当我们希望使用将以上的数据解析为List时需要这样写。

Gson gson = new Gson();
String jsonArray = "[\"Android\",\"Java\",\"PHP\"]";
String[] strings = gson.fromJson(jsonArray, String[].class);
List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>() {}.getType());

注:TypeToken的构造方法是protected修饰的,所以上面才会写成new TypeToken>() {}.getType() 而不是 new TypeToken>().getType()

泛型解析对接口POJO的设计影响
泛型的引入可以减少无关的代码,如我现在所在公司接口返回的数据分为两类:

{"code":"0","message":"success","data":{}}
{"code":"0","message":"success","data":[]}

我们真正需要的data所包含的数据,而code只使用一次,message则几乎不用。如果Gson不支持泛型或不知道Gson支持泛型的同学一定会这么定义POJO。

public class UserResponse {
    public int code;
    public String message;
    public User data;
}

当其它接口的时候又重新定义一个XXResponsedata的类型改成XX,很明显code,和message被重复定义了多次,通过泛型的话我们可以将codemessage字段抽取到一个Result的类中,这样我们只需要编写data字段所对应的POJO即可,更专注于我们的业务逻辑。如:

public class Result<T> {
    public int code;
    public String message;
    public T data;
}

// 使用
// 不再重复定义Result类
Type userType = new TypeToken<Result<User>>(){}.getType();
Result<User> userResult = gson.fromJson(json,userType);
User user = userResult.data;

Type userListType = new TypeToken<Result<List<User>>>(){}.getType();
Result<List<User>> userListResult = gson.fromJson(json,userListType);
List<User> users = userListResult.data;

那么对于data字段是User时则可以写为 Result ,当是个列表的时候为 Result>,其它同理。

对于泛型封装可以参考: 《搞定Gson泛型封装》

自定义解析

由于js和java的命名方式不同,如js采用下划线_连接命名而java采用驼峰命名,此时前后端的字段无法对应,导致映射失败,可以采用自定义解析方式,规定规则,或者采用注解方式。

GsonBuilder

定制gson实例对象中的解析方式

Gson gson = new GsonBuilder()     
.registerTypeAdapter(Id.class, new IdTypeAdapter())   
.enableComplexMapKeySerialization()
.serializeNulls()   
.setDateFormat(DateFormat.LONG)  
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)//会把字段首字母大写
.setPrettyPrinting()
.setVersion(1.0)    
.create();

此处我们关注setFieldNamingPolicy方法即可,传入解析命名规则:

Enum ConstantDescription
IDENTITY原样解析
LOWER_CASE_WITH_DASHES将Java驼峰规则转换为小写用 - 连接的字段来映射
LOWER_CASE_WITH_DOTS将Java驼峰规则转换为小写用 . 连接的字段来映射
LOWER_CASE_WITH_UNDERSCORES将Java驼峰规则转换为小写用 _ 连接的字段来映射
UPPER_CAMEL_CASE将Java驼峰规则转换为首字母也大写的规则
UPPER_CAMEL_CASE_WITH_SPACES将Java驼峰规则转换为首字母也大写,且使用空格分割

其余属性均可在该网站查询到:

  1. setFieldNamingPolicy 设置序列字段的命名策略(UPPER_CAMEL_CASE,UPPER_CAMEL_CASE_WITH_SPACES,LOWER_CASE_WITH_UNDERSCORES,LOWER_CASE_WITH_DASHES)
  2. addDeserializationExclusionStrategy 设置反序列化时字段采用策略ExclusionStrategy,如反序列化时不要某字段,当然可以采用@Expore代替。
  3. excludeFieldsWithoutExposeAnnotation 设置没有@Expore则不序列化和反序列化
  4. addSerializationExclusionStrategy 设置序列化时字段采用策略,如序列化时不要某字段,当然可以采用@Expore代替。
  5. registerTypeAdapter 为某特定对象设置固定的序列和反序列方式,实现JsonSerializer和JsonDeserializer接口
  6. setFieldNamingStrategy 设置字段序列和反序列时名称显示,也可以通过@Serializer代替
  7. setPrettyPrinting 设置gson转换后的字符串为一个比较好看的字符串
  8. setDateFormat 设置默认Date解析时对应的format格式
@Expose注解

如果采用new Gson()方式创建Gson则@Expose则没有任何效果,若采用GsonBuilder创建Gson并且调用了excludeFieldsWithoutExposeAnnotation则@Expose将会影响toJson和fromGson序列化和反序列化数据。

public class User {
    @Expose private String firstName;
    @Expose(serialize = false) private String lastName;
    @Expose(serialize = false, deserialize = false) private String emailAddress;
    private String password;
 }

例子中password不管是toJson还是fromJson都不会用到,emailAddress和lastName在序列化(fromJson)时将被采用,emailAddress在反序列化(toJson)时将不被采用。

@SerializedName注解

该注解标注在JavaBean的字段上,用于候选对应解析的字段

@SerializedName 注解解决 JSON 字符串键名称和 POJO 类属性名不对应的问题

// 如果json字符串为
String jsonStr="{'my_name':'pp'}";

// JavaBean中name字段为
@SerializedName("my_name")
private String myName;

SerializedName注解提供了两个属性,上面用到了其中一个,别外还有一个属性alternate,接收一个String数组。
注:alternate需要2.4版本

@SerializedName(value = "emailAddress", alternate = {"email", "email_address"})
public String emailAddress;

注意:当上面的三个属性(email_address、email、emailAddress)都中出现任意一个时均可以得到正确的结果。
注:当多种情况同时出时,以最后一个出现的值为准。

解析复杂对象

参考:https://www.jianshu.com/p/185e1ee9f05b


本文参考资料:

https://www.jianshu.com/p/31396863d1aa

https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/FieldNamingPolicy.html

https://www.jianshu.com/p/558844c96fc1

https://github.com/google/gson/blob/master/UserGuide.md

https://www.jianshu.com/p/e740196225a4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值