美文网首页Android开发Android开发
使用Gson解决的问题汇总

使用Gson解决的问题汇总

作者: 巴黎没有摩天轮Li | 来源:发表于2020-05-20 21:46 被阅读0次

前言

Gson是谷歌提供的解析Json的库,使用非常方便,并且采用了很多设计模式,是一个很优秀的工具库,因此我这里记录一下使用Gson的一些心得。

问题一

最近公司准备将项目的一个子业务接口换掉,奈何之前后端采用PHP开发,字段首字母全部大写,而后新接口采用驼峰式命名,因此字段更替是一个十分恼人的事情。不太想一个一个的去改JsonBean,所以想看看Json反序列化的过程中有没有什么取巧的方式。
为了解决该问题,我去看了下Gson的源码:

Gson(Excluder excluder, FieldNamingStrategy fieldNamingStrategy,
      Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls,
      boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
      boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues,
      LongSerializationPolicy longSerializationPolicy, String datePattern, int dateStyle,
      int timeStyle, List<TypeAdapterFactory> builderFactories,
      List<TypeAdapterFactory> builderHierarchyFactories,
      List<TypeAdapterFactory> factoriesToBeAdded) {
    // ...省略一系列构造方法赋值操作
    List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
    factories.add(TypeAdapters.STRING_FACTORY);
    factories.add(TypeAdapters.INTEGER_FACTORY);
    // ... 以下省略多种解析类型
    // type adapters for composite and user-defined types
    factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
    factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
    this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor);
    factories.add(jsonAdapterFactory);
    factories.add(TypeAdapters.ENUM_FACTORY);
    factories.add(new ReflectiveTypeAdapterFactory(
        constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));
    this.factories = Collections.unmodifiableList(factories);
  }

这里我简单说一下后续会写一篇专门分析Gson源码的文章。Gson通过TypeAdapter去识别字段类型并解析,提前将一些常用的类型的解析实现类存储在集合中,常用类型保存完毕,之后最后添加了一个ReflectiveTypeAdapterFactory类,这个类专门用于解析自定义类型Json对象,我们注意去关注这个类。之前在使用Gson的时候,经常使用一个注解@SerializedName,这个可以将json字段名称转换成自定义名称,所以针对这次的业务问题我想从这里的源代码分析入手看看有没有好的切入点。

    /**
     * nameLi : JSON
     * addressLi : 北京市西城区
     * ageLi : 25
     */
    // 自定义字段名称 可选字段名称 一般用于容错处理
    @SerializedName(value = "nameLi1", alternate = {"nameLi2"})
    private String NameLi;
    private String AddressLi;
    private int AgeLi;
/** 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;
  }

这里发现当@SerializedName没有注解到字段上时会去调用一个FieldNamingPolicy,典型的策略设计模式。因此我们知道可以自定义一个命名解析规则,哈哈,可以不用加班了~

public interface FieldNamingStrategy {

  /**
   * Translates the field name into its JSON field name representation.
   *
   * @param f the field object that we are translating
   * @return the translated field name.
   * @since 1.3
   */
  public String translateName(Field f);
}

可见是一个接口,因此我们实现它:

class MyFieldNamingStrategy : FieldNamingStrategy {
    override fun translateName(f: Field): String {
        val s = f.name
        if (s == "VipNo") {
            return "UserId"
        }
        return if (Character.isLowerCase(s[0])) {
            s
        } else {
            Character.toLowerCase(s[0]).toString() + s.substring(1)
        }
    }
}

可见这样处理就完成了,我们通过反射更改Field的变量名称,还可以将VipNo 改为 UserId。注意的是还记得刚才的源码么 一旦字段被@SerializedName注解的,这里就会失效,目前针对我的问题只能手动改了,或者去掉注解,还好用的这个注解不多。

使用方式

  val gson = GsonBuilder().setFieldNamingStrategy(MyFieldNamingStrategy()).create()
  val testEntity = gson.fromJson(json, TestEntity::class.java)

其实这里Gson提供我们一些实现好的策略

// 枚举类型策略
public enum FieldNamingPolicy implements FieldNamingStrategy {
    IDENTITY,// 默认的方式 接口字段是什么样式对应JsonBean就是什么字段样式
    UPPER_CAMEL_CASE,// someFieldName ---> SomeFieldName 反过来竟然没实现😂
    UPPER_CAMEL_CASE_WITH_SPACES,// someFieldName ---> Some Field Name
    LOWER_CASE_WITH_UNDERSCORES,// someFieldName ---> some_field_name
    LOWER_CASE_WITH_DASHES,// someFieldName ---> some-field-name
    LOWER_CASE_WITH_DOTS // someFieldName ---> some.field.name
}

相关文章

  • 使用Gson解决的问题汇总

    前言 Gson是谷歌提供的解析Json的库,使用非常方便,并且采用了很多设计模式,是一个很优秀的工具库,因此我这里...

  • 关于Gson解析的使用汇总

    JsonPrimitive的使用 参考:1 关于Gson解析的使用汇总

  • java.lang.IllegalStateException:

    我在使用retrofit和Gson配合时,出现了这个问题,疑惑中乱七八糟瞎搞了一个下午没有解决。期间怀疑Gson解...

  • 数据解析之返回格式为数组

    解决步骤:1:使用Gson gson.toJson 先转为String2:再转为相应集合数据代码:

  • Andriod中Gson使用

    Gson使用 参考你真的会用Gson吗?Gson使用指南 在Android中使用Gson,先在Compile中加入...

  • Gson使用指南 2017-08-15

    Gson使用指南系列其它文章你真的会用Gson吗?Gson使用指南(一)你真的会用Gson吗?Gson使用指南(二...

  • gson解析对象闪退

    问题描述: 在使用谷歌的gson把对象转成json时老是卡住,闪退。 String json =new Gson(...

  • Java中将JSON反序列化为泛型对象

    将嵌套List的Map转换为Json应该都没什么问题,使用Gson和Jackson都能实现,在Gson中使用new...

  • gson的使用细节

    关于json,gson是最常用到的一个库。平常使用时我通常使用Gson gson = new Gson();的方式...

  • Android 库 Gson

    【Android 库 Gson】 引用: ★Gson 解析教程★★★ Gson的入门使用Gson全解析(上)-Gs...

网友评论

    本文标题:使用Gson解决的问题汇总

    本文链接:https://www.haomeiwen.com/subject/jjroohtx.html