json - Gson 的意外行为

标签 json gson java-9 jlink jdeps

我开发了一个存储来自设备的数据的小型应用程序:我选择以 JSON 格式存储数据,并且数据的序列化/反序列化工作得很好,即使它涉及我创建的一些自定义类型......但只有我在 IDE 中工作(Eclipse,就此而言)。
但是,当我导出可运行的 JAR 文件时,数据的反序列化会遇到某种问题,因为软件总是抛出这个异常:

Caused by: java.lang.UnsupportedOperationException: Cannot allocate class LocalDateTime
    at com.google.gson.internal.UnsafeAllocator$4.newInstance(UnsafeAllocator.java:104)
    at com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:225)
    ... 88 common frames omitted
我以为我会遇到自定义类型的问题,而不是内置类型。在这一点上,我发现了两件事:
  • 如果我使用完整的 JRE 9 运行 JAR 文件,则不会引发异常:我仔细检查了使用 Jlink.exe 创建的自定义 JRE 中包含的模块,并且所有内容都正确包含。我仍然想使用更小的 JRE,所以我还没有进一步调查(我想这解释了为什么在 IDE 中它可以完美运行)
  • 我向 Gson 对象添加了一个自定义反序列化器(见下文),我只是手动将 JSON 字符串转换为有效数据,并且避免了 LocalDateTime 类上的异常......但异常再次出现在另一个类上,这个时间定制一个。

  • 在这一点上,我想我可以简单地为导致问题的每种数据类型添加一个反序列化器,但我想知道 为什么完整的 JRE 不会出现此问题,以及为什么较小的 JRE 会导致此问题 ,即使包括了所有必需的模块。也许值得一提的是,我没有向保存数据的 Gson 对象添加自定义序列化程序,它全部按照 Gson 默认进行序列化。LocalDateTime解串器:
        @Override
        public LocalDateTime deserialize(JsonElement json, java.lang.reflect.Type type,
                    JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
    
            JsonObject joDate = json.getAsJsonObject().get("date").getAsJsonObject();
            JsonObject joTime = json.getAsJsonObject().get("time").getAsJsonObject();
            //JSON example: {"date":{"year":2019,"month":1,"day":9},"time":{"hour":6,"minute":14,"second":1,"nano":0}
            return LocalDateTime.of(joDate.get("year").getAsInt(),
                    joDate.get("month").getAsInt(),
                    joDate.get("day").getAsInt(),
                    joTime.get("hour").getAsInt(),
                    joTime.get("minute").getAsInt(),
                    joTime.get("second").getAsInt(),
                    joTime.get("nano").getAsInt());
        }
    }
    
    Jdeps.deps 模块列表:
    com.google.gson
    java.base
    javafx.base
    javafx.controls
    javafx.fxml
    javafx.graphics
    org.slf4j
    

    收到答复后,我打开了一个问题 here .

    最佳答案

    TL;博士

    您需要一个包含模块 jdk.unsupported 的运行时镜像(例如完整的 JDK 或使用 jlink 构建的东西)。

    完整答案

    GSON 希望在不调用任何构造函数的情况下创建它反序列化的类的实例(因此,如果没有 GSON 这么说,什么都不会被初始化)。这通常不能完成,但是 sun.misc.Unsafe提供了一种使用方法 allocateInstance 来执行此操作的方法.为此,GSON 需要 sun.misc.Unsafe 的实例.调用堆栈中最顶层的帧来自 UnsafeAllocator , 它使用 common trickery to get Unsafe .

    问题是,sun.misc.Unsafe位于模块 jdk.unsupported 中,该模块存在于完整的 JDK 中,但通常不会在运行时镜像中找到。

    使用 jlink 创建运行时镜像时,请确保包含选项 --add-modules jdk.unsupported你应该很高兴。

    可以说,GSON 应该声明一个 optional dependency在 jdk.unsupported with requires static .

    关于json - Gson 的意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61727613/

    相关文章:

    javascript - 将 text.json 解析为 jquery.animation?

    java - Gson 和 Jackson 不兼容

    java - 在 JAVA 中使用 GSON 序列化内部类

    java - 我怎样才能获得 JAVA 9 JRE/JDK 作为 zip 文件而不是 EXE 或 MSI 安装程序?

    java - 如何从 Json 转换为 Protobuf?

    Javascript/JSON 获取给定子节点的路径?

    java - 使用 JSON (GSON) 将 PHP 关联数组传输到 Java Map<String, Double>

    java - List.of() 或 Collections.emptyList()

    Java 9 --release 标志似乎在 Gradle 中不起作用

    javascript - 处理 JSON 响应时出错。意想不到的角色