Gson 轻松处理 json 和实体类的属性名不一样

Gson 解析之 - 如何让 json 键和实体类的属性名不一样

最近Gson用的比较多,用的时候一直有一个疑问,难道本地的实体类的属性名一定要和Json的键一一对应吗?

json数据

{
  "name": "wangzhen",
  "age": 20,
  "tall": "176",
  "sex": "male"
}

对应的实体类

public class Person1 {
    String name;
    String age;
    String sex;
    String tall;
}

一切看起来都是那么的美好,但是如果有一天,我们从另一个接口上,请求下来的数据是这样的呢?

{
  "person_name": "wangzhen",
  "person_age": 20,
  "tall": "176",
  "person_sex": "male"
}

那我们的实体类岂不是要写成这样?

public class Person2 {
    String first_name;
    String person_name;
    String person_age;
    String person_sex;
}

可以试一下Person1

    Gson gson = new Gson();
    InputStream inputStream = null;
    inputStream = new FileInputStream(new File("json file path"));
    InStream2String converter = new InStream2String();
    String json = converter.convert(inputStream);
    Person person = gson.fromJson(json, Person1.class);
    System.out.println(person);

=== output ===
Person1{name='null', age='null', sex='null', tall='176'}

简直不能忍
可是有什么办法吗?想到的一个解决方案就是为每一个实体类的属性添加一个注解,在注解中标明该属性对应json的值,比如上面的 json 的 person_name 应该对应 Person 的 name 属性。
有思路就简单咯,自己动手丰衣足食

新建一个注解,就叫Map吧

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Map {
    String value();
}

现在的属性应该是这个样子的,有点感觉了。

@Map("person_name") String name;
@Map("person_age") String age;
@Map("person_sex") String sex;

在运行时,只需要动态获取注解里面的值,就可以得到当前属性应当对应的json的键,所以就可以起到属性名与json键不同的效果了
好了,只需要去 818 Gson的源码,然后用一个装饰模式为Gson动态的添加一个职责差不多咯

(这种方式就是写段源码解析   初中级不建议自己实现 费时费力很大程度上写的还不如现成的)

但是! too young, too naive!

跟踪源码的时候发现,会调用
com.google.gson.internal.bind.ReflectiveTypeAdapterFactory
这个类中的 这个方法

  private String getFieldName(Field f) {
    SerializedName serializedName = f.getAnnotation(SerializedName.class);
    return serializedName == null ? fieldNamingPolicy.translateName(f) : serializedName.value();
  }

尼玛,这 SerializedName又是什么鬼。。
点进去看一下

SerializedName注解的源码:

/**
 * An annotation that indicates this member should be serialized to JSON with
 * the provided name value as its field name.
 *
 * <p>This annotation will override any {@link com.google.gson.FieldNamingPolicy}, including
 * the default field naming policy, that may have been set on the {@link com.google.gson.Gson}
 * instance.  A different naming policy can set using the {@code GsonBuilder} class.  See
 * {@link com.google.gson.GsonBuilder#setFieldNamingPolicy(com.google.gson.FieldNamingPolicy)}
 * for more information.</p>
 *
 * <p>Here is an example of how this annotation is meant to be used:</p>
 * <pre>
 * public class SomeClassWithFields {
 *   &#64SerializedName("name") private final String someField;
 *   private final String someOtherField;
 *
 *   public SomeClassWithFields(String a, String b) {
 *     this.someField = a;
 *     this.someOtherField = b;
 *   }
 * }
 * </pre>
 *
 * <p>The following shows the output that is generated when serializing an instance of the
 * above example class:</p>
 * <pre>
 * SomeClassWithFields objectToSerialize = new SomeClassWithFields("a", "b");
 * Gson gson = new Gson();
 * String jsonRepresentation = gson.toJson(objectToSerialize);
 * System.out.println(jsonRepresentation);
 *
 * ===== OUTPUT =====
 * {"name":"a","someOtherField":"b"}
 * </pre>
 *
 * <p>NOTE: The value you specify in this annotation must be a valid JSON field name.</p>
 *
 * @see com.google.gson.FieldNamingPolicy
 *
 * @author Inderjeet Singh
 * @author Joel Leitch
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SerializedName {

  /**
   * @return the desired name of the field when it is serialized
   */
  String value();
}

这。。。。。
结合上面的getFieldName方法,Gson在获取属性名的时候会先判断SerializedName注解的值,如果有就使用 SerializedName的值(value)作为属性名。
好了,轮子造到一半让Google给截胡了。但,省了很多事啊哈哈哈哈哈哈哈哈。

忽略上面的笑声

好了,你的实体类的属性现在应该长这模样,至于其他的,小伙伴们一起探索咯

@SerializedName("person_name") 
String name;
@SerializedName("person_age") 
String age;
@SerializedName("person_sex") 
String sex;


或者
 @SerializedName(value = "name", alternate = {"Name", "studentName", "fullName"})
String name;

复制记录学习一下
作者:氢电公敌
链接:https://www.jianshu.com/p/867798e8b627

 

 

JAVA学习网站

http://how2j.cn?p=73013

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值