首页 > 开发 > 综合 > 正文

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

2024-07-21 23:03:51
字体:
来源:转载
供稿:网友

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

总结

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


注:相关教程知识阅读请移步到kotlin教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表