在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的类
翻译如下:
宽松地说,返回直接被该元素包围的元素。 类或接口被认为包含它直接声明的字段、方法、构造函数和成员类型。 包包含其中的顶级类和接口,但不被视为包含子包。 模块将包包含在其中。 封闭的元素可以包括隐式声明的强制元素。 其他种类的元素目前不被认为包含任何元素; 但是,随着 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 枚举0反射,同样的读写都是o(1)
更多类型的实现 请参考我的开源项目 gson_plugin
这个可能是业界最快的json解析方式 最快的json解析框架