当前位置: 移动技术网 > 移动技术>移动开发>Android > kotlin gson反序列化默认值失效深入讲解

kotlin gson反序列化默认值失效深入讲解

2019年07月30日  | 移动技术网移动技术  | 我要评论

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")
 }
}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对移动技术网的支持。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网