GSON JSON 序列化 - 无法使字段私有 int java.sql.Timestamp.nanos 可访问

GSON JSON serialization - Unable to make field private int java.sql.Timestamp.nanos accessible

提问人:Felix 提问时间:10/30/2023 更新时间:11/17/2023 访问量:76

问:

自从最近的 Java 升级以来,我们无法序列化从 SQL 数据库读取的对象,其值映射到 .底层数据库是 SAP Sybase,我们的客户能够通过像 这样简单的查询来重现该问题。java.sql.TimestampSelect getdate()

环境:Java 17.0.4.1、Eclipse Adoptium、Mac OS X 14.0

这不是我们添加或类似选项的选项。我还尝试调试到 Gson 库中,发现该对象使用了“反射适配器”。add-opens=java.sql=ALL-UNNAMEDTypeAdapterRuntimeTypeWrapperjava.sql.Timestamp

作为一种解决方法,我现在使用 Jackson 库作为后备,它能够毫无问题地序列化我的对象(即下面代码中的第二个 try 子句可以正常工作):

try {
    json = GSON.toJson(object);
} catch (Exception e) {
    log.warn("Failed to serialize JSON. Trying alternative serializer (1).", e);
    try {
        json = new ObjectMapper().writeValueAsString(object);
    } catch (Exception e1) {
        log.warn("Failed to serialize JSON. Leaving null.", e);
    }
}

堆栈跟踪:

com.google.gson.JsonIOException: Failed making field 'java.sql.Timestamp#nanos' accessible; either increase its visibility or write a custom TypeAdapter for its declaring type.
    at com.google.gson.internal.reflect.ReflectionHelper.makeAccessible(ReflectionHelper.java:38)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:286)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:130)
    at com.google.gson.Gson.getAdapter(Gson.java:556)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:55)
    at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:207)
    at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:144)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:70)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:97)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:61)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:70)
    at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:207)
    at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:144)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:70)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:97)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:61)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:70)
    at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:207)
    at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:144)
    at com.google.gson.Gson.toJson(Gson.java:842)
    at com.google.gson.Gson.toJson(Gson.java:812)
    at com.google.gson.Gson.toJson(Gson.java:759)
    at com.google.gson.Gson.toJson(Gson.java:736)
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private int java.sql.Timestamp.nanos accessible: module java.sql does not "opens java.sql" to unnamed module @2554782d
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(Unknown Source)
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(Unknown Source)
    at java.base/java.lang.reflect.Field.checkCanSetAccessible(Unknown Source)
    at java.base/java.lang.reflect.Field.setAccessible(Unknown Source)
    at com.google.gson.internal.reflect.ReflectionHelper.makeAccessible(ReflectionHelper.java:35)

有什么想法吗?

java json 杰克逊 gson sybase

评论

0赞 SpaceTrucker 10/30/2023
这种序列化时间戳的 json 应该是什么样子的?
0赞 SedJ601 10/31/2023
这是吗?看看这些信息是否能在这里帮助你JavaFXmodule-info.java
0赞 Marcono1234 10/31/2023
Gson 应该有一个专用的 java.sql.Timestamp 适配器,但也许 Gson 中的逻辑有缺陷并且由于某种原因没有应用?您能否调试并检查内部 Gson 类的行为方式?但是,Gson 的内置适配器使用的格式可能不是必需的,因此您可能需要编写自定义适配器SqlTypesSupport

答:

0赞 mariusi 11/17/2023 #1

看来你必须编写自己的TypeAdapter。或者为失败的特定类型添加排除项。在故障排除指南中发现:https://github.com/google/gson/blob/main/Troubleshooting.md#-inaccessibleobjectexception-module--does-not-opens--to-unnamed-module 有确切的错误,您的解决方法看起来也很好。