【问题标题】:GSON unable to serialize exception with Java 17GSON 无法使用 Java 17 序列化异常
【发布时间】:2021-12-16 09:04:09
【问题描述】:

以下代码用于 Java 11:

new Gson().toJson(new Exception())

在 JDK 17 上出现以下错误:

Unable to make field private java.lang.String java.lang.Throwable.detailMessage accessible: module java.base does not "opens java.lang" to unnamed module @147ed70f

通过阅读this page,我想我可以用--add-opens java.base/java.lang=ALL-UNNAMED 解决它。然而有更好的方法吗?也许使用自定义反序列化器?

【问题讨论】:

  • 你为什么要序列化一个类,它的结构只能在版本之间改变,或者在不同的 JDK/JRE 实现之间可能不同,这完全破坏了你的设计?你根本无法控制它。 Gson,按照设计,对它不知道的对象使用反射(没有注册特殊类型的适配器),因此它只是遍历所有对象字段,无论它们是公共的还是私有的。外国图书馆的私人资料绝不是要这样连载的。从不。
  • 我们有两个服务。当 A 调用 B 时,B 可以抛出异常。我将其序列化并将其传递回 A,因此 A 可以将其作为引发异常的原因包含在内。它对调查崩溃很有用;我没有意识到这是一个禁忌。
  • 是的,我理解目的,但是您需要自己的数据传输对象 (DTO) 来承载异常数据,以便您的 DTO 完全由您控制,并决定应该从哪些数据中获取可能具有比我想象的更多私有字段的异常(私有字段、包私有或私有类、各种引用或循环引用等)。它将需要一些代码从 exe 映射到 DTO(然后在必要时返回到 exe),但是您将永远不会仅使用 Throwables 的公共 API 遇到此类问题。

标签: java gson


【解决方案1】:

这是我添加的用于反序列化异常的代码。这可以在这样的类中使用:

public class Result {
    public final Object result;
    public final Error error;

    public Result(Object result) { ... }

    public Result(Exception e) {
        this.result = null;
        this.error = new Error(e);
    }
}

另一方面,请致电result.error.toThrowable()

public static class Error {
    public final String message;
    public final List<STE> stackTrace;
    public final Error cause;

    public Error(Throwable e) {
        message = e.getMessage();
        stackTrace = Arrays.stream(e.getStackTrace()).map(STE::new).collect(Collectors.toList());
        cause = e.getCause() != null ? new Error(e.getCause()) : null;
    }

    public Throwable toThrowable() {
        Throwable t = new Throwable(message);
        t.setStackTrace(stackTrace.stream().map(STE::toStackTraceElement).toArray(StackTraceElement[]::new));
        if (cause != null) {
            t.initCause(cause.toThrowable());
        }
        return t;
    }

    private static class STE {
        public final String declaringClass;
        public final String methodName;
        public final String fileName;
        public final int    lineNumber;

        public STE(StackTraceElement ste) {
            this.declaringClass = ste.getClassName();
            this.methodName = ste.getMethodName();
            this.fileName = ste.getFileName();
            this.lineNumber = ste.getLineNumber();
        }

        public StackTraceElement toStackTraceElement() {
            return new StackTraceElement(declaringClass, methodName, fileName, lineNumber);
        }
    }
}

【讨论】:

    【解决方案2】:

    我昨天有这个。我使用的是 Java 17。我回到 Java 11,它运行良好。

    我想是因为这个:https://bugs.openjdk.java.net/browse/JDK-8256358

    我很懒,使用 GSON 默认反射类型适配器。

    你必须实现你自己的 TypeAdapter 来修复它。或者也许使用另一个 JSON 反序列化器,比如 Jackson,我稍后可能会这样做。

    【讨论】:

      猜你喜欢
      • 2017-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-07
      • 2017-09-04
      • 2014-05-22
      相关资源
      最近更新 更多