@SerializedName注解的意义

当我们使用Gson解析Json数据时都会创建一个对应实体类,有时候Json数据里面的字段是Java关键词或者Json数据里面的字段太简单,我们想在实体类中自定义字段名,这时就可以用@SerializedName注解。

@SerializedName注解,不管是对象转Json还是Json转对象,字段名称会被替换成注解的名字。

@SerializedName这个注解解决了我们Model和Json不对应的问题,好处:

  1. 首先将服务器字段和客户端字段名称区分,不用保持一一对应关系,客户端定义的字段不用根据服务端接口字段改变而改变,只需要更改@SerializedName中的取值即可;
  2. 我们输出一个Json格式的数据也可以使用@SerializedName不用为了输出格式而影响java中驼峰命名规范;

实例

    public class Test {

    public static void main(String[] args) {
Gson gson = new Gson();
User user = new User("juneyu", "18");
String json = gson.toJson(user);
System.out.println("obj->json:" + json);
User user2 = gson.fromJson(json, User.class);
System.out.println("json->obj:" + user2);
} public static class User{
@SerializedName("Name")
private String name;
@SerializedName("Age")
private String age; public User(String name, String age) {
this.name = name;
this.age = age;
} @Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}

输出为:

obj->json:{"Name":"juneyu","Age":"18"}
json->obj:User{name='juneyu', age='18'}

实现原理

查看Gson源码,在ReflectiveTypeAdapterFactory类中有如下代码:

  private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) {
Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
if (raw.isInterface()) {
return result;
} 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;
}
field.setAccessible(true);
Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
List<String> fieldNames = getFieldNames(field);
BoundField previous = null;
for (int i = 0; i < fieldNames.size(); ++i) {
String name = fieldNames.get(i);
if (i != 0) serialize = false; // only serialize the default name
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;
} /** first element holds the default name */
private List<String> getFieldNames(Field f) {
SerializedName annotation = f.getAnnotation(SerializedName.class);
if (annotation == null) {
String name = fieldNamingPolicy.translateName(f);
return Collections.singletonList(name);
} String serializedName = annotation.value();
String[] alternates = annotation.alternate();
if (alternates.length == 0) {
return Collections.singletonList(serializedName);
} List<String> fieldNames = new ArrayList<String>(alternates.length + 1);
fieldNames.add(serializedName);
for (String alternate : alternates) {
fieldNames.add(alternate);
}
return fieldNames;
}

在getFieldNames方法中,在获取Field时去匹配了SerializedName注解类标示的字段,存在的话取的是注解设定的值。

其它

情况一:多个字段取一个

项目中只用了一个字段来更改解析字段名,还有一种情况,我们在开发的时候会用到,这里举一个不太合适的例子,例如:后台同学给配数据,后期要废弃其中一个字段,但又不能影响老版本的使用,于是增加了一个字段,取值相同。

解决:

当然我们在新版本直接将字段改成新字段取值就好了。

这是一种解决办法,但是不能保证以后没有其它字段废弃或者添加,这里在介绍一个属性alternate简明知意,用来替换;

可以这么写:

  @SerializedName(value = "Name", alternate = {"NameNew"})

当出现Name或者NameNew字段时,就会主动匹配,当然如果都存在就匹配最后一个,这样在老版本上虽然服务器返回的是增加NameNew的数据,但是客户端使用的是@SerializedName("Name") 来解析的,所以也不会出问题,在新版本上使用NameNew字段,等完全替代老版本以后,就可以在服务器中去掉原来的Name字段,当然我这种情况是比较理想的,一般也不会说随意更改字段含义,但也不排除这种可能,如果有那我们自然应对就好。

注意:

1、千万注意要解析成对象的类,和对象转成Json的类,不要去混淆,否则会解析不成功,在Android中可以修改proguard-project.txt文件来过滤不混淆的类;

2、需要注入到JS当中的类不能混淆;

3、另外在使用Gson和FastJson中,发现 FastJson 在某些情况下内部会出现空指针,而且数据解析有可能不正确,项目中遇到一次在某条数据下出问题,然后替换了Gson就好了,具体区别还查证;

4、自己使用的时候尽量封装以下,避免以后换库导致修改地方过多;

Android探究之Gson@SerializedName的更多相关文章

  1. Android中使用Gson解析JSON数据的两种方法

    Json是一种类似于XML的通用数据交换格式,具有比XML更高的传输效率;本文将介绍两种方法解析JSON数据,需要的朋友可以参考下   Json是一种类似于XML的通用数据交换格式,具有比XML更高的 ...

  2. Android Volley和Gson实现网络数据加载

    Android Volley和Gson实现网络数据加载 先看接口 1 升级接口 http://s.meibeike.com/mcloud/ota/cloudService POST请求 参数列表如下 ...

  3. Android中使用Gson解析JSON数据

      Android中使用Gson解析JSON数据 在Android中可以使用Gson解析JSON数据 首先,从 code.google.com/p/google-gson/downloads/list ...

  4. Android开源库--Gson谷歌官方json解析库

    官方文档地址:http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/index.html 官方网站:http://code.go ...

  5. Android JSON、GSON、FastJson的封装与解析

    声明: 1.本帖只提供代码,不深入讲解原理.如果读者想要深入了解,那就不要在这个帖子上浪费时间了 2.客户端用的是Google官方的Volley访问服务器,具体了解Volley请戳 这里 3.本帖三种 ...

  6. 【Android】使用Gson和Post请求和服务器通信

    一.需求文档如下: URL:http://108.188.129.56:8080/example/cal 请求格式: {"para1":10,"para2":2 ...

  7. [转] Android:用GSON 五招之内搞定任何JSON数组

    [From] http://www.open-open.com/lib/view/open1472632967912.html 写在前面 关于GSON的入门级使用,这里就不提了,如有需要可以看这篇博文 ...

  8. Android笔记:gson处理多层嵌套的复杂形式的json

    当一个Class的字段属性中包含另一个class时gson能正常处理吗? 最初看到网上有说使用static的说法 经验证是不需要的 直接当普通类来用就可以了. 直接使用gson.fromJson方法即 ...

  9. 【Android进阶】Gson解析json字符串的简单应用

    在客户端与服务器之间进行数据传输,一般采用两种数据格式,一种是xml,一种是json.这两种数据交换形式各有千秋,比如使用json数据格式,数据量会比较小,传输速度快,放便解析,而采用xml数据格式, ...

随机推荐

  1. jenkins + supervisor + ansible 实现netcore程序的多机一键部署

    上一篇我们简单的说到了使用jenkins+supervisor实现了一个单机版的多副本部署,但是在更多的场景下还是需要netcore程序的多机一键部署,那么多 机器间如何分发呢? 肯定不能使用scp这 ...

  2. Hibernate学习——持久化类的学习

    A.概念 持久化:将内存中的对象持久化(存储)到数据库的过程.Hibernate就是持久化的框架. 持久化类:一个普通java对象与数据库的表建立了映射关系,那么这个类在Hiberna中被称为持久化类 ...

  3. SQL Server AlwaysOn 集群 关于主Server IP与Listener IP调换的详细测试

    1. 背景 SQL Server 搭建AlwaysOn后,我们就希望程序连接时使用虚拟的侦听IP(Listener IP),而不再是主Server 的IP.如果我们有采用中间件,则可以在配置中,直接用 ...

  4. Mongo之架构部署(Replica Sets+Sharding)

    一.环境 要构建一个 MongoDB Sharding Cluster,需要三种角色: •Shard Server: mongod 实例,用于存储实际的数据块. •Config Server: mon ...

  5. sqlserver—数据完整性(理论篇)

    数据完整性主要指的是数据的精确性和可靠性,目的就是为了防止数据库中存放的数值,以及字符具有合法性(即按照管理员定义的规则进行存放) 分为以下四类: 实体完整性 实体完整性要求每一个表中的主键字段都不能 ...

  6. Windows10文件目录下添加 Shift+右键打开管理员Powershell窗口

    背景(可略过) 目前在调试 Python 程序,遇到了一个问题:当程序中包含多线程时,使用 IDLE 运行是不会执行多线程的语句的,在网上一顿搜罗了解到这种情况可以换成在命令行下执行.好像用 PyCh ...

  7. Java中char,short,int,long占几个字节和多少位

    1.字节:byte:用来计量存储容量的一种计量单位:位:bit 2.一个字节等于8位  1byte = 8bit char占用的是2个字节 16位,所以一个char类型的可以存储一个汉字. 整型: b ...

  8. MySql开启慢查询日志并使用pt-query-digest 分析

    慢查询日志会将查询过程中超出你设置的时间的查询记录下来,以便供开发者进行分析和优化. 1. 开启慢查询 1.1 查看当前设置 mysql> show variables like "% ...

  9. Android 开发之v4库冲突问题解决方案说明

    问题背景 Android Studio 开发时使用到了 GSYVideoPlayer 开源的播放器框架,配置信息如下: implementation 'com.shuyu:GSYVideoPlayer ...

  10. springboot的war和jar包

    本篇和大家分享的是通过maven对springboot中打war包和jar包:war通常来说生成后直接放到tomcat的webapps下面就行,tomcat配置自动解压war,而jar一般通过命令行部 ...