【问题标题】:Gson deserialization works stranglyGson 反序列化工作异常
【发布时间】:2021-01-19 07:45:00
【问题描述】:

今天我发现了 Gson 的一些奇怪行为。假设我们有以下简单的 JSON

{
    "a": {
        "foo": 123
    }
}

用对应的类表示


class A(val foo: Int)

class B(val a: A) {
    val foo = a.foo
}

但是,请注意,AfooB 中有一个“快捷方式”。而且问题是在GSON反序列化过程中,这个字段没有初始化。意思是assertEquals(123, b.foo) 失败。

首先我查看了生成的字节码,将其反编译,但看起来还不错:


 public static final class A {
      private final int foo;

      public final int getFoo() {
         return this.foo;
      }

      public A(int foo) {
         this.foo = foo;
      }
   }

public static final class B {
      private final int foo;
      @NotNull
      private final SubscriptionChangeTest.A a;

      public final int getFoo() {
         return this.foo;
      }

      @NotNull
      public final SubscriptionChangeTest.A getA() {
         return this.a;
      }

      public B(@NotNull SubscriptionChangeTest.A a) {
         Intrinsics.checkNotNullParameter(a, "a");
         super();
         this.a = a;
         this.foo = this.a.getFoo();
      }
   }

我看到的唯一原因是 GSON 不调用构造函数,而是在创建对象后使用反射填充那些 final 字段。如果您能分享您对此的想法,我将不胜感激。提前致谢。

P.S 他们的问题不是如何修复它,它很简单(将 B.foo 更改为 getter 属性),而是它为什么会这样工作

【问题讨论】:

  • 这样的设计选择保证不调用构造函数和访问器(因此根本没有命令式代码)可以为任何使用ReflectiveTypeAdapterFactory序列化/反序列化的对象进行完美的序列化/反序列化往返(不包括未声明字段的接口和必须扩展为“成为”可实例化的抽象类)。
  • @fluffy 但在最近的 Java 版本中,Unsafe 不是无法访问吗?我的意思是,例如 Gson 可能不适用于 Java 11
  • 可能。我还没有使用过 Java 9 及更高版本。如果他们,Gson 开发人员,能够从一开始就窥视未来,他们可能会做出另一种设计选择。 Gson 声称是一个 Java 6 库,因此他们甚至没有 Java 8 的类型适配器(Time API、Optional 等)。我最近知道的唯一一件事是他们添加了一些模块支持以在 Java 9 中运行。无论如何,实现一个实例创建器就可以了。

标签: json kotlin gson


【解决方案1】:

事实证明,Gson 确实不调用构造函数,而是使用sun.misc.unsafe 创建对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多