kotlin gson反序列化默认值失效深入讲解
时间:2022-07-28
本文章向大家介绍kotlin gson反序列化默认值失效深入讲解,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
Gson反序列化原理
原理简述
gson反序列化主要分为两个过程:
- 根据TypeToken创建出对象
- 根据json字符串解析数据,对对象属性赋值
对象的创建
ConstructorConstructor.get
- 先尝试获取无参构造函数
- 失败则尝试List、Map等情况的构造函数
- 最后使用Unsafe.newInstance兜底(此兜底不会调用构造函数,导致所有对象初始化代码不会调用)
public <T ObjectConstructor<T get(TypeToken<T typeToken) {
final Type type = typeToken.getType();
final Class<? super T rawType = typeToken.getRawType();
// first try an instance creator
@SuppressWarnings("unchecked") // types must agree
final InstanceCreator<T typeCreator = (InstanceCreator<T ) instanceCreators.get(type);
if (typeCreator != null) {
return new ObjectConstructor<T () {
@Override public T construct() {
return typeCreator.createInstance(type);
}
};
}
// Next try raw type match for instance creators
@SuppressWarnings("unchecked") // types must agree
final InstanceCreator<T rawTypeCreator =
(InstanceCreator<T ) instanceCreators.get(rawType);
if (rawTypeCreator != null) {
return new ObjectConstructor<T () {
@Override public T construct() {
return rawTypeCreator.createInstance(type);
}
};
}
// 获取无参构造函数
ObjectConstructor<T defaultConstructor = newDefaultConstructor(rawType);
if (defaultConstructor != null) {
return defaultConstructor;
}
// 获取List<T ,Map<T 等构造函数,对于List,Map的情况
ObjectConstructor<T defaultImplementation = newDefaultImplementationConstructor(type, rawType);
if (defaultImplementation != null) {
return defaultImplementation;
}
// unSafe构造出对象,不调用任何的构造函数
// finally try unsafe
return newUnsafeAllocator(type, rawType);
}
ConstructorConstructor.newDefaultConstructor
- 调用Class.getDeclaredConstructor获取无参构造函数
private <T ObjectConstructor<T newDefaultConstructor(Class<? super T rawType) {
try {
// 获取无参构造函数
final Constructor<? super T constructor = rawType.getDeclaredConstructor();
if (!constructor.isAccessible()) {
accessor.makeAccessible(constructor);
}
ConstructorConstructor.newUnsafeAllocator
- 调用UnSafe.newInstance创建出对象
- 不会调用构造函数,因此所有的初始化的代码都不会被调用
private <T ObjectConstructor<T newUnsafeAllocator(
final Type type, final Class<? super T rawType) {
return new ObjectConstructor<T () {
private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
@SuppressWarnings("unchecked")
@Override public T construct() {
try {
//
Object newInstance = unsafeAllocator.newInstance(rawType);
return (T) newInstance;
} catch (Exception e) {
throw new RuntimeException(("Unable to invoke no-args constructor for " + type + ". "
+ "Registering an InstanceCreator with Gson for this type may fix this problem."), e);
}
}
};
}
结论
- Gson反序列要工作正常,使结果符合预期的话,要求类必须有一个无参构造函数
kotlin构造函数默认参数和无参构造函数的关系
参数里面存在没有默认值的情况
kotlin代码
- id没有默认值
class User(val id: Int, val name: String = "sss") {
init {
println("init")
}
}
反编译的Java代码
- 包含两个构造函数,一个是我们声明的全参数构造函数,另一个是kotlin生成的辅助构造函数
- 不包含无参构造函数
public final class User {
private final int id;
@NotNull
private final String name;
public User(int id, @NotNull String name) {
Intrinsics.checkParameterIsNotNull(name, "name");
super();
this.id = id;
this.name = name;
String var3 = "init";
System.out.println(var3);
}
// $FF: synthetic method
public User(int var1, String var2, int var3, DefaultConstructorMarker var4) {
if ((var3 & 2) != 0) {
var2 = "";
}
this(var1, var2);
}
}
gson反序列化输出
代码:
@Test
fun testJson() {
val user = Gson().fromJson("{}", User::class.java)
print(user.name)
}
输出:不符合预期(我们声明的非空的name实际结果是null)
null Process finished with exit code 0
参数都包含默认参数的情况
kotlin代码
class User(val id: Int=1, val name: String = "sss") {
init {
println("init")
}
}
反编译Java代码
- 除了上面的两个构造函数,多了一个无参构造函数(从逻辑上讲,这个也符合预期)
public final class User {
private final int id;
@NotNull
private final String name;
public User(int id, @NotNull String name) {
Intrinsics.checkParameterIsNotNull(name, "name");
super();
this.id = id;
this.name = name;
String var3 = "init";
System.out.println(var3);
}
// $FF: synthetic method
public User(int var1, String var2, int var3, DefaultConstructorMarker var4) {
if ((var3 & 1) != 0) {
var1 = 1;
}
if ((var3 & 2) != 0) {
var2 = "";
}
this(var1, var2);
}
// 无参构造函数
public User() {
this(0, (String)null, 3, (DefaultConstructorMarker)null);
}
}
gson反序列化输出
代码:
@Test
fun testJson() {
val user = Gson().fromJson("{}", User::class.java)
print(user.name)
}
输出:符合预期
init sss Process finished with exit code 0
Best Practice
Practice1
- 属性声明在构造函数,所有参数都带默认值
- 不确定的参数声明为可空
class User(val id: Int=1 , val name: String = "sss") {
init {
println("init")
}
}
Practice2
回归到Java的写法即可
class User {
val id: Int = 1
val name: String = "sss"
init {
println("init")
}
}
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对ZaLou.Cn的支持。
- React第三方组件2(状态管理之Refast的使用②异步修改state)
- UVa Automatic Editing
- React第三方组件2(状态管理之Refast的使用①简单使用)
- uva Excuses, Excuses!
- React第三方组件5(状态管理之Redux的使用④TodoList下)
- 2017/6/9-Python文件读写的方法
- React第三方组件5(状态管理之Redux的使用③TodoList中)
- R语言在收入不平等指标测度上的应用~
- React第三方组件5(状态管理之Redux的使用②TodoList上)
- sscanf
- sprintf的用法
- 01背包精讲
- uva Andy's First Dictionary
- UVA Hangman Judge
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 关于laravel 子查询 & join的使用
- PHPUnit + Laravel单元测试常用技能
- php接口隔离原则实例分析
- laravel实现按月或天或小时统计mysql数据的方法
- laravel model模型处理之修改查询或修改字段时的类型格式案例
- 对laravel的session获取与存取方法详解
- php 中self,this的区别和操作方法实例分析
- Laravel使用原生sql语句并调用的方法
- Yii框架自定义数据库操作组件示例
- laravel 使用事件系统统计浏览量的实现
- PHP之多条件混合筛选功能的实现方法
- PHP多进程简单实例小结
- 解决laravel5中auth用户登录其他页面获取不到登录信息的问题
- Yii框架学习笔记之应用组件操作示例
- laravel 之 Eloquent 模型修改器和序列化示例