kotlin gson反序列化默认值失效

栏目: 服务器 · 发布时间: 7年前

内容简介:gson反序列化主要分为两个过程:ConstructorConstructor.getConstructorConstructor.newDefaultConstructor

gson反序列化主要分为两个过程:

  1. 根据TypeToken创建出对象
  2. 根据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")
    }
}
复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

More Eric Meyer on CSS (Voices That Matter)

More Eric Meyer on CSS (Voices That Matter)

Eric A. Meyer / New Riders Press / 2004-04-08 / USD 45.00

Ready to commit to using more CSS on your sites? If you are a hands-on learner who has been toying with CSS and want to experiment with real-world projects that will enable you to see how CSS......一起来看看 《More Eric Meyer on CSS (Voices That Matter)》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

SHA 加密
SHA 加密

SHA 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具