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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。