'GSON unable to serialize exception with Java 17

The following code used to work on Java 11:

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

On JDK 17 I get the following error:

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

From reading this page, I think I could resolve it with --add-opens java.base/java.lang=ALL-UNNAMED. Is there a better way however? Perhaps with a custom de/serializer?



Solution 1:[1]

Here's the code I added to de/serialize exceptions. This can be used in a class like this:

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);
    }
}

And the on the other, call 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);
        }
    }
}

Solution 2:[2]

I had this yesterday. I was using Java 17. I went back to Java 11 and it worked fine.

I think it's because of this: https://bugs.openjdk.java.net/browse/JDK-8256358

I am lazy and using the GSON default reflection type adapter.

You have to implement your own TypeAdapter to fix it. Or perhaps use another JSON deserializer like Jackson, which I might do later.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Malcolm Crum
Solution 2 Matt McEwan