kotlin gson反序列化默认值失效深入讲解
Gson反序列化原理
原理简述
gson反序列化主要分为两个过程:
- 根据TypeToken创建出对象
- 根据json字符串解析数据,对对象属性赋值
对象的创建
ConstructorConstructor.get
- 先尝试获取无参构造函数
- 失败则尝试List、Map等情况的构造函数
- 最后使用Unsafe.newInstance兜底(此兜底不会调用构造函数,导致所有对象初始化代码不会调用)
publicObjectConstructor get(TypeToken typeToken){ finalTypetype=typeToken.getType(); finalClassrawType=typeToken.getRawType(); //firsttryaninstancecreator @SuppressWarnings("unchecked")//typesmustagree finalInstanceCreator typeCreator=(InstanceCreator )instanceCreators.get(type); if(typeCreator!=null){ returnnewObjectConstructor (){ @OverridepublicTconstruct(){ returntypeCreator.createInstance(type); } }; } //Nexttryrawtypematchforinstancecreators @SuppressWarnings("unchecked")//typesmustagree finalInstanceCreator rawTypeCreator= (InstanceCreator )instanceCreators.get(rawType); if(rawTypeCreator!=null){ returnnewObjectConstructor (){ @OverridepublicTconstruct(){ returnrawTypeCreator.createInstance(type); } }; } //获取无参构造函数 ObjectConstructor defaultConstructor=newDefaultConstructor(rawType); if(defaultConstructor!=null){ returndefaultConstructor; } //获取List ,Map 等构造函数,对于List,Map的情况 ObjectConstructor defaultImplementation=newDefaultImplementationConstructor(type,rawType); if(defaultImplementation!=null){ returndefaultImplementation; } //unSafe构造出对象,不调用任何的构造函数 //finallytryunsafe returnnewUnsafeAllocator(type,rawType); }
ConstructorConstructor.newDefaultConstructor
- 调用Class.getDeclaredConstructor获取无参构造函数
privateObjectConstructor newDefaultConstructor(ClassrawType){ try{ //获取无参构造函数 finalConstructorconstructor=rawType.getDeclaredConstructor(); if(!constructor.isAccessible()){ accessor.makeAccessible(constructor); }
ConstructorConstructor.newUnsafeAllocator
- 调用UnSafe.newInstance创建出对象
- 不会调用构造函数,因此所有的初始化的代码都不会被调用
privateObjectConstructor newUnsafeAllocator( finalTypetype,finalClassrawType){ returnnewObjectConstructor (){ privatefinalUnsafeAllocatorunsafeAllocator=UnsafeAllocator.create(); @SuppressWarnings("unchecked") @OverridepublicTconstruct(){ try{ // ObjectnewInstance=unsafeAllocator.newInstance(rawType); return(T)newInstance; }catch(Exceptione){ thrownewRuntimeException(("Unabletoinvokeno-argsconstructorfor"+type+"." +"RegisteringanInstanceCreatorwithGsonforthistypemayfixthisproblem."),e); } } }; }
结论
- Gson反序列要工作正常,使结果符合预期的话,要求类必须有一个无参构造函数
kotlin构造函数默认参数和无参构造函数的关系
参数里面存在没有默认值的情况
kotlin代码
- id没有默认值
classUser(valid:Int,valname:String="sss"){
init{
println("init")
}
}
反编译的Java代码
- 包含两个构造函数,一个是我们声明的全参数构造函数,另一个是kotlin生成的辅助构造函数
- 不包含无参构造函数
publicfinalclassUser{
privatefinalintid;
@NotNull
privatefinalStringname;
publicUser(intid,@NotNullStringname){
Intrinsics.checkParameterIsNotNull(name,"name");
super();
this.id=id;
this.name=name;
Stringvar3="init";
System.out.println(var3);
}
//$FF:syntheticmethod
publicUser(intvar1,Stringvar2,intvar3,DefaultConstructorMarkervar4){
if((var3&2)!=0){
var2="";
}
this(var1,var2);
}
}
gson反序列化输出
代码:
@Test
funtestJson(){
valuser=Gson().fromJson("{}",User::class.java)
print(user.name)
}
输出:不符合预期(我们声明的非空的name实际结果是null)
null
Processfinishedwithexitcode0
参数都包含默认参数的情况
kotlin代码
classUser(valid:Int=1,valname:String="sss"){
init{
println("init")
}
}
反编译Java代码
- 除了上面的两个构造函数,多了一个无参构造函数(从逻辑上讲,这个也符合预期)
publicfinalclassUser{
privatefinalintid;
@NotNull
privatefinalStringname;
publicUser(intid,@NotNullStringname){
Intrinsics.checkParameterIsNotNull(name,"name");
super();
this.id=id;
this.name=name;
Stringvar3="init";
System.out.println(var3);
}
//$FF:syntheticmethod
publicUser(intvar1,Stringvar2,intvar3,DefaultConstructorMarkervar4){
if((var3&1)!=0){
var1=1;
}
if((var3&2)!=0){
var2="";
}
this(var1,var2);
}
//无参构造函数
publicUser(){
this(0,(String)null,3,(DefaultConstructorMarker)null);
}
}
gson反序列化输出
代码:
@Test
funtestJson(){
valuser=Gson().fromJson("{}",User::class.java)
print(user.name)
}
输出:符合预期
init
sss
Processfinishedwithexitcode0
BestPractice
Practice1
- 属性声明在构造函数,所有参数都带默认值
- 不确定的参数声明为可空
classUser(valid:Int=1,valname:String="sss"){
init{
println("init")
}
}
Practice2
回归到Java的写法即可
classUser{
valid:Int=1
valname:String="sss"
init{
println("init")
}
}
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。