Gson 自动生成适配器插件

在json解析方面 我们常见有下面几方面困扰

1. moshi code-gen能自动生成适配器,序列化效率比gson快,但是自定义程度不如gson,能java kotlin共存 且解决了默认值的问题
2.gson api 强大自由,但是 第一次gson的反射缓存比较慢,而且生成对象都是反射,除非主动注册com.google.gson.InstanceCreator 这个人工机械
3.kotlin ks 效率还行,但是不支持java  api自由性没有gson强
目前可能更偏向gson 同时也要解决默认值的问题

最大的一处难点是在jvm 获取申明的枚举,先看一下gson是怎么解决的
 

  private static final class EnumTypeAdapter> extends TypeAdapter {
    private final Map nameToConstant = new HashMap();
    private final Map constantToName = new HashMap();

    public EnumTypeAdapter(final Class classOfT) {
      try {
        // Uses reflection to find enum constants to work around name mismatches for obfuscated classes
        // Reflection access might throw SecurityException, therefore run this in privileged context;
        // should be acceptable because this only retrieves enum constants, but does not expose anything else
        Field[] constantFields = AccessController.doPrivileged(new PrivilegedAction() {
          @Override public Field[] run() {
            Field[] fields = classOfT.getDeclaredFields();
            ArrayList constantFieldsList = new ArrayList(fields.length);
            for (Field f : fields) {
              if (f.isEnumConstant()) {
                constantFieldsList.add(f);
              }
            }

            Field[] constantFields = constantFieldsList.toArray(new Field[0]);
            AccessibleObject.setAccessible(constantFields, true);
            return constantFields;
          }
        });
        for (Field constantField : constantFields) {
          @SuppressWarnings("unchecked")
          T constant = (T)(constantField.get(null));
          String name = constant.name();
          SerializedName annotation = constantField.getAnnotation(SerializedName.class);
          if (annotation != null) {
            name = annotation.value();
            for (String alternate : annotation.alternate()) {
              nameToConstant.put(alternate, constant);
            }
          }
          nameToConstant.put(name, constant);
          constantToName.put(constant, name);
        }
      } catch (IllegalAccessException e) {
        throw new AssertionError(e);
      }
    }
    @Override public T read(JsonReader in) throws IOException {
      if (in.peek() == JsonToken.NULL) {
        in.nextNull();
        return null;
      }
      return nameToConstant.get(in.nextString());
    }

    @Override public void write(JsonWriter out, T value) throws IOException {
      out.value(value == null ? null : constantToName.get(value));
    }
  }

gson的实现 是第一次反射(TypeAdapter 对于rawType gson本身会缓存)
他这个时候能读取到class,但是编译注解这个时候并不能得到class,
那么又查询了官方文档,官方的解释不在是class 而是Element和TypeName的类

Gson 自动生成适配器插件_第1张图片

翻译如下:
宽松地说,返回直接被该元素包围的元素。 类或接口被认为包含它直接声明的字段、方法、构造函数和成员类型。 包包含其中的顶级类和接口,但不被视为包含子包。 模块将包包含在其中。 封闭的元素可以包括隐式声明的强制元素。 其他种类的元素目前不被认为包含任何元素; 但是,随着 API 或编程语言的发展,这种情况可能会发生变化。
返回:
包含的元素,如果没有则为空列表
API注意事项:
可以使用 ElementFilter 中的方法来隔离某些类型的元素。
也可以看看:
TypeElement.getEnclosureElements、PackageElement.getEnheldElements、ModuleElement.getEnheldElements、Elements.getAllMembers
吉林斯
8.8.9 默认构造函数
吉林斯
8.9 枚举
修改
9
规格
联合项目管理系统

那么我理解jvm 元数据matadata存储在这个数组里面

我打印了一下 得到枚举的全部申明 包括enum_entry(不是enum class)还有valueOf等方法

枚举数据在元数据里面 values(),valueOf(java.lang.String),HELLO,HI,FINE,THANKS,intValue,TestEnum(int),getIntValue()

得按类型过滤出 申明的enum_constant

        val enumConstants = enumElement?.enclosedElements?.filter {
            it.kind == ElementKind.ENUM_CONSTANT
        } ?: listOf()

最终折腾了半天 终于出来了


import com.google.gson.annotations.SerializedName
import javax.lang.model.element.ElementKind

/**
 * xxf:生成编译时枚举常量池生成hashmap
 */
internal class EnumTypeParser {
    internal val nameToConstant: MutableMap = mutableMapOf()
    internal val constantToName: MutableMap = mutableMapOf()

    /**
     * 枚举数据在元数据里面 values(),valueOf(java.lang.String),HELLO,HI,FINE,THANKS,intValue,TestEnum(int),getIntValue()
     * @param enumElement
     */
    constructor(enumElement: javax.lang.model.element.Element?) {
        val enumConstants = enumElement?.enclosedElements?.filter {
            it.kind == ElementKind.ENUM_CONSTANT
        } ?: listOf()
        enumConstants.forEach { constant ->
            val annotation: SerializedName? = constant.getAnnotation(SerializedName::class.java)

            var name = constant.simpleName.toString()
            //本身名字
            nameToConstant[name] = constant


            //注解名字 和别名名字
            if (annotation != null) {
                name = annotation.value
                for (alternate in annotation.alternate) {
                    nameToConstant[alternate] = constant
                }
            }

            nameToConstant[name] = constant
            constantToName[constant] = name
        }
        //排序一下 代码好看一点
        nameToConstant.toSortedMap().run {
            nameToConstant.clear()
            nameToConstant.putAll(this)
        }

        //排序一下 代码好看一点
        constantToName.toSortedMap(Comparator { o1, o2 ->
            constantToName[o1]!!.compareTo(constantToName[o2]!!)
        }).run {
            constantToName.clear()
            constantToName.putAll(this)
        }
    }

}

运行效果:Gson 自动生成适配器插件_第2张图片

Gson 自动生成适配器插件_第3张图片

这样就替代了gson 枚举0反射,同样的读写都是o(1)

更多类型的实现 请参考我的开源项目 gson_plugin
这个可能是业界最快的json解析方式 最快的json解析框架

你可能感兴趣的:(java,json,json,零反射,gson,提升速度,json解析速度最快的方式)