先来看一段代码,@SerializedName的具体用法如下:
那这个注解有何作用呢?
答案:解决后台返回json字段名称在客户端不好用的问题。
举例:
后台接口返回json数据如下:
{
"id":"1"
"n":"zhangsan"
"p":"123456"
"s":"0"
}
这是一个user的数据包括id、用户名、密码、性别,如果正常些一个user类来解析的话是这样的:
public class User{
private String id;
private String n;
private String p;
private String s;
}
如果通过Gson直接解析json,User.n 表示name会非常不利于阅读,如果后台接口基于统一开发原因不好修改或开发人员难以沟通、不想修改,客户端又不能妥协的情况下,这时候@SerializedName注解就派上用场了:
public class User{
private String id;
@SerializedName("n")
private String userName;
@SerializedName("p")
private String password;
@SerializedName("s")
private String sex;
}
Gson解析的时候会自动将n对应的值赋值到userName属性上,
同样,如果要将User生成json字符串,使用Gson生成的时候也会将userName的名字生成n。
这样就解决了java对象里属性名跟json里字段名不匹配的情况了。
细心的同学会发现:不对啊,示例代码是这样写的:
public @SerializedName("results") List<GankBeauty> beauties;
而你写成这样:
@SerializedName("results")
public List<GankBeauty> beauties;
两者其实一样。可以把@SerializedName看作一个修饰词,修饰变量beauties。
实现原理
查看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注解类标示的字段,存在的话取的是注解设定的值。
其他需要注意的地方:
1、不要去混淆:要解析成对象的类、对象转成Json的类,否则会解析不成功,可在Android中可以修改proguard-project.txt文件实现
2、需要注入到JS当中的类不能混淆;