Android探究之[email protected]

@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、自己使用的时候尽量封装以下,避免以后换库导致修改地方过多;

原文地址:https://www.cnblogs.com/juneyu/p/10122171.html

时间: 2024-11-13 06:49:08

Android探究之[email protected]的相关文章

Android Studio 获取 [email&#160;protected]

WIN+R   打开“运行”  输入  CMD 回车 2 CD C:\Program Files\Java\jdk1.7.0_71\bin     (JDK安装路径) keytool -list -v -keystore c:\users\your_user_name\.android\debug.keystore -alias androiddebugkey -storepass android -keypass android 例如:keytool -list -v -keystore c:

Android Studio:Unable to add window [email&#160;protected] -- permission denied for this window 第一行代码

学习<第一行代码>的时候,出现的错误. java.lang.RuntimeException: Unable to start receiver com.example.sevenun.littledemo.receiver.ForceOfflineReceiver: android.view.WindowManager$BadTokenException: Unable to add window [email protected] -- permission denied for this

[email&#160;protected]:在PC屏幕上显示Android手机屏幕

这里介绍一款工具——[email protected],用来获取手机屏幕,显示在PC屏幕上.它集截图.录像等多种功能于一体. 安装 1.    下载地址:http://droid-at-screen.org/download.html,下载后是一个jar包,放到某个目录就可以. 2.    安装JDK6或以上版本 3.    安装Android SDK(从Android官方下载一个完整包解压即可) 4.    设置ANDROID_HOME环境变量指向AndroidSDK主目录(这步如果不做,则需

Android Unable to add window -- token [email&#160;protected] is not valid错误分析记录

打开APP时,出现闪退的情况,查看android studio报错信息,主要为: Unable to add window -- token [email protected] is not valid 原因分析:由于进入APP时会显示一个进度对话框,对话框的初始化必须依赖Activity,但如果对话框的初始化放在Activity的onCreate方法中,那么就会报错. 因为根据Activity的生命周期,onCreate方法执行时,Activity并未创建完毕,对话框所依赖的Activity还

Android: Unable to resolve dependency for &#39;:[email&#160;protected]/compileClasspath&#39;:

我按照ExoPlayer的github指引添加 implementation 'com.google.android.exoplayer:exoplayer:2.X.X' 发现根本run不起来,并报错如题 后来在stackoverflow找到了解决方案,来源为:https://stackoverflow.com/questions/46949622/android-studio-3-0-unable-to-resolve-dependency-for-appdexoptions-compilec

android studio怎么分享项目到[email&#160;protected]托管

鄙人初次发表,如有不妥之处,敬请批评指正 1,安装git. git下载地址:http://git-scm.com/downloads/ 2,在AS 的File->Settings->Version Control->Git 配置git.exe命令路径,如下图: 配置AS 的git 配置完成后,如果点击"Test" 按钮提示successfully,则说明配置成功. 3.在[email protected]上创建仓库,获取仓库地址. 现在这里我的仓库地址是:https:

Unable to add window -- token [email&#160;protected] is not valid错误分析记录

打开APP时,出现闪退的情况,查看android studio报错信息,主要为: Unable to add window -- token [email protected] is not valid 原因分析:由于进入APP时会显示一个进度对话框,对话框的初始化必须依赖Activity,但如果对话框的初始化放在Activity的onCreate方法中,那么就会报错. 因为根据Activity的生命周期,onCreate方法执行时,Activity并未创建完毕,对话框所依赖的Activity还

解决has leaked ServiceConnection [email&#160;protected]

解决"has leaked ServiceConnection [email protected] that was originally bound here"的错误,需要修改AndroidManifest.xml文件. 配置Map定位权限和远程链接机制.不然,就会报下面的错误: has leaked ServiceConnection [email protected] that was originally bound here android.app.ServiceConnec

Canvas: trying to use a recycled bitmap [email&#160;protected]

近期在做和图片相关显示的出现了一个问题,整理一下思路.分享出来给大家參考一下: Exception Type:java.lang.RuntimeException java.lang.RuntimeException: Canvas: trying to use a recycled bitmap [email protected] at android.graphics.Canvas.throwIfCannotDraw(Canvas.java:1282) at android.view.GLE