当前位置: 首页 > article >正文

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<T extends Enum<T>> extends TypeAdapter<T> {
    private final Map<String, T> nameToConstant = new HashMap<String, T>();
    private final Map<T, String> constantToName = new HashMap<T, String>();

    public EnumTypeAdapter(final Class<T> 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<Field[]>() {
          @Override public Field[] run() {
            Field[] fields = classOfT.getDeclaredFields();
            ArrayList<Field> constantFieldsList = new ArrayList<Field>(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的类

翻译如下:
宽松地说,返回直接被该元素包围的元素。 类或接口被认为包含它直接声明的字段、方法、构造函数和成员类型。 包包含其中的顶级类和接口,但不被视为包含子包。 模块将包包含在其中。 封闭的元素可以包括隐式声明的强制元素。 其他种类的元素目前不被认为包含任何元素; 但是,随着 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<String, Any> = mutableMapOf()
    internal val constantToName: MutableMap<Any, String> = 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 枚举0反射,同样的读写都是o(1)

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


http://www.kler.cn/a/157168.html

相关文章:

  • javaweb 04 springmvc
  • Vue(四)
  • matplotlib pyton 如何画柱状图,利用kimi,直接把图拉倒上面,让他生成
  • Ubuntu网络配置(桥接模式, nat模式, host主机模式)
  • 论文研读:AnimateDiff—通过微调SD,用图片生成动画
  • MyBatis如何处理延迟加载?
  • cocos creator-碰撞检测
  • STM32串口接收不定长数据(空闲中断+DMA)
  • 调试GMS应用,报错“此设备未获得play保护机制认证”问题解决
  • 马斯克极简5步工作法 —— 筑梦之路
  • 大数据技术学习笔记(四)—— HDFS
  • Java生成word[doc格式转docx]
  • 【开源】基于JAVA的天然气工程运维系统
  • ffmpeg学习日记619-指令-透明通道视频相关指令
  • Cpp之旅(学习笔记)第9章 标准库
  • Ant Design Pro初始化报错
  • 为什么要做ERP集成?ERP系统如何与其他业务应用程序集成
  • 装箱 Box 数据类型
  • Metasploit的网络流量分析和嗅探
  • SQL手工注入漏洞测试(PostgreSQL数据库)-墨者
  • 面试官:说说synchronized与ReentrantLock的区别
  • 训练 CNN 对 CIFAR-10 数据中的图像进行分类-keras实现
  • 【黑马甄选离线数仓day08_会员主题域开发】
  • 【STM32】TIM定时器输出比较
  • 中英翻译数据集处理
  • JFrog----常见的开源协议以及应用注意点