From 7648fad723ed78d59a7ad5aa4d0521381a98865b Mon Sep 17 00:00:00 2001 From: Vasiliy Mikhailov Date: Mon, 22 Jun 2026 10:27:16 +0300 Subject: [PATCH] Rethrow Error from @PostConstruct method instead of wrapping it in RuntimeException PostConstructAdapterFactory rethrows a RuntimeException cause as-is but wraps everything else. An Error thrown by the @PostConstruct method (AssertionError, OutOfMemoryError, ...) is unchecked like RuntimeException and should propagate as-is, not be smothered in a RuntimeException. Rethrow Error the same way. Adds a regression test. --- .../PostConstructAdapterFactory.java | 2 ++ .../PostConstructAdapterFactoryTest.java | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/extras/src/main/java/com/google/gson/typeadapters/PostConstructAdapterFactory.java b/extras/src/main/java/com/google/gson/typeadapters/PostConstructAdapterFactory.java index 924a9089ff..cc731085f5 100644 --- a/extras/src/main/java/com/google/gson/typeadapters/PostConstructAdapterFactory.java +++ b/extras/src/main/java/com/google/gson/typeadapters/PostConstructAdapterFactory.java @@ -65,6 +65,8 @@ public T read(JsonReader in) throws IOException { } catch (InvocationTargetException e) { if (e.getCause() instanceof RuntimeException) { throw (RuntimeException) e.getCause(); + } else if (e.getCause() instanceof Error) { + throw (Error) e.getCause(); } throw new RuntimeException(e.getCause()); } diff --git a/extras/src/test/java/com/google/gson/typeadapters/PostConstructAdapterFactoryTest.java b/extras/src/test/java/com/google/gson/typeadapters/PostConstructAdapterFactoryTest.java index a46fa3089b..943bd11798 100644 --- a/extras/src/test/java/com/google/gson/typeadapters/PostConstructAdapterFactoryTest.java +++ b/extras/src/test/java/com/google/gson/typeadapters/PostConstructAdapterFactoryTest.java @@ -95,6 +95,37 @@ public boolean equals(Object o) { } } + @Test + public void testErrorFromPostConstructPropagatesAsError() { + Gson gson = + new GsonBuilder().registerTypeAdapterFactory(new PostConstructAdapterFactory()).create(); + + CustomTestError thrown = + assertThrows( + CustomTestError.class, () -> gson.fromJson("{\"value\": 1}", ErrorThrowingClass.class)); + + assertThat(thrown).hasMessageThat().isEqualTo("error from post-construct"); + } + + static class ErrorThrowingClass { + public int value; + + @PostConstruct + private void init() { + throw new CustomTestError("error from post-construct"); + } + } + + // A dedicated Error subclass so the test does not rely on a JDK Error type (e.g. AssertionError, + // which Gson re-tags with a version prefix) and is not confused with a meaningful JVM error. + private static final class CustomTestError extends Error { + private static final long serialVersionUID = 1L; + + CustomTestError(String message) { + super(message); + } + } + @SuppressWarnings({"overrides", "EqualsHashCode"}) // for missing hashCode() override static class MultipleSandwiches { public List sandwiches;