当咱们使用Gson解析Json数据时都会建立一个对应实体类,有时候Json数据里面的字段是Java关键词或者Json数据里面的字段太简单,咱们想在实体类中自定义字段名,这时就能够用@SerializedName注解。java
@SerializedName注解,无论是对象转Json仍是Json转对象,字段名称会被替换成注解的名字。json
@SerializedName这个注解解决了咱们Model和Json不对应的问题,好处:服务器
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 + '\'' + '}'; } }
输出为:ide
obj->json:{"Name":"juneyu","Age":"18"} json->obj:User{name='juneyu', age='18'}
查看Gson源码,在ReflectiveTypeAdapterFactory类中有以下代码:this
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注解类标示的字段,存在的话取的是注解设定的值。指针
状况一:多个字段取一个code
项目中只用了一个字段来更改解析字段名,还有一种状况,咱们在开发的时候会用到,这里举一个不太合适的例子,例如:后台同窗给配数据,后期要废弃其中一个字段,但又不能影响老版本的使用,因而增长了一个字段,取值相同。对象
解决:接口
固然咱们在新版本直接将字段改为新字段取值就行了。
这是一种解决办法,可是不能保证之后没有其它字段废弃或者添加,这里在介绍一个属性alternate简明知意,用来替换;
能够这么写:ip
@SerializedName(value = "Name", alternate = {"NameNew"})
当出现Name或者NameNew字段时,就会主动匹配,固然若是都存在就匹配最后一个,这样在老版本上虽然服务器返回的是增长NameNew的数据,可是客户端使用的是@SerializedName("Name") 来解析的,因此也不会出问题,在新版本上使用NameNew字段,等彻底替代老版本之后,就能够在服务器中去掉原来的Name字段,固然我这种状况是比较理想的,通常也不会说随意更改字段含义,但也不排除这种可能,若是有那咱们天然应对就好。
注意:
一、千万注意要解析成对象的类,和对象转成Json的类,不要去混淆,不然会解析不成功,在Android中能够修改proguard-project.txt文件来过滤不混淆的类;
二、须要注入到JS当中的类不能混淆;
三、另外在使用Gson和FastJson中,发现 FastJson 在某些状况下内部会出现空指针,并且数据解析有可能不正确,项目中遇到一次在某条数据下出问题,而后替换了Gson就行了,具体区别还查证;
四、本身使用的时候尽可能封装如下,避免之后换库致使修改地方过多;