Skip to content

Commit 487a9fd

Browse files
committed
Merge branch '2.x' into 3.x
2 parents 918064d + 8c52e1f commit 487a9fd

File tree

3 files changed

+82
-2
lines changed

3 files changed

+82
-2
lines changed

release-notes/VERSION-2.x

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ Project: jackson-databind
2222
#5192: Record types are broken on Android when using R8
2323
(reported by @HelloOO7)
2424
(fix by @pjfanning)
25+
#5194: Custom `Throwable` not serializable if using `JsonAutoDetect` settings
26+
that only detect Fields
27+
(reported by @riskop)
2528
#5197: Add more informative exception for back-references with `record` type
2629
(fix by Joo-Hyuk K)
2730
- Generate SBOMs [JSTEP-14]

src/main/java/tools/jackson/databind/ser/BeanPropertyWriter.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -772,13 +772,25 @@ protected boolean _handleSelfReference(Object bean, JsonGenerator g,
772772
throws JacksonException
773773
{
774774
if (!ser.usesObjectId()) {
775+
boolean writeAsNull = false;
776+
775777
if (ctxt.isEnabled(SerializationFeature.FAIL_ON_SELF_REFERENCES)) {
776778
// 05-Feb-2013, tatu: Usually a problem, but NOT if we are handling
777779
// object id; this may be the case for BeanSerializers at least.
778780
if (ser instanceof BeanSerializerBase) {
779-
ctxt.reportBadDefinition(getType(), "Direct self-reference leading to cycle");
781+
// 09-Jul-2025, tatu: [databind#5194] Let's suppress specific case
782+
// of "cause" for Throwables
783+
if (_isThrowableFieldCause(ctxt, bean)) {
784+
writeAsNull = true;
785+
} else {
786+
ctxt.reportBadDefinition(getType(), "Direct self-reference leading to cycle");
787+
}
780788
}
781-
} else if (ctxt.isEnabled(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL)) {
789+
} else {
790+
writeAsNull = ctxt.isEnabled(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL);
791+
}
792+
793+
if (writeAsNull) {
782794
if (_nullSerializer != null) {
783795
// 23-Oct-2019, tatu: Tricky part -- caller does not specify if it's
784796
// "as property" (in JSON Object) or "as element" (JSON array, via
@@ -796,6 +808,17 @@ protected boolean _handleSelfReference(Object bean, JsonGenerator g,
796808
return false;
797809
}
798810

811+
// Helper method to recognize `Throwable.cause` Field, which has "this" as initialized
812+
// value to mean "not set" (`Throwable.getCause()` translates this to `null`).
813+
//
814+
// @since 2.20
815+
private boolean _isThrowableFieldCause(SerializationContext ctxt, Object bean) {
816+
return bean instanceof Throwable
817+
&& _member instanceof AnnotatedField
818+
&& "cause".equals(_name.getValue())
819+
;
820+
}
821+
799822
@Override
800823
public String toString() {
801824
StringBuilder sb = new StringBuilder(40);
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package tools.jackson.databind.ser.jdk;
2+
3+
import org.junit.jupiter.api.Disabled;
4+
import org.junit.jupiter.api.Test;
5+
6+
import com.fasterxml.jackson.annotation.JsonAutoDetect;
7+
import com.fasterxml.jackson.annotation.PropertyAccessor;
8+
import tools.jackson.databind.*;
9+
import tools.jackson.databind.json.JsonMapper;
10+
import tools.jackson.databind.testutil.DatabindTestUtil;
11+
12+
import static org.junit.jupiter.api.Assertions.assertNotNull;
13+
14+
public class CustomExceptionSer5194Test
15+
extends DatabindTestUtil
16+
{
17+
static class MyIllegalArgumentException extends RuntimeException {
18+
private static final long serialVersionUID = 1L;
19+
20+
public MyIllegalArgumentException() {
21+
super();
22+
}
23+
24+
public MyIllegalArgumentException(String s) {
25+
super(s);
26+
}
27+
28+
public MyIllegalArgumentException(String message, Throwable cause) {
29+
super(message, cause);
30+
}
31+
32+
public MyIllegalArgumentException(Throwable cause) {
33+
super(cause);
34+
}
35+
}
36+
37+
// [databind#5194]: failed to serialize custom exception
38+
// 09-Jul-2025, tatu: Works for 2.x, fails for 3.x -- no idea why, disabled for now
39+
@Disabled
40+
@Test
41+
public void test5194() throws Exception {
42+
ObjectMapper mapper = JsonMapper.builder()
43+
.changeDefaultVisibility(vc -> vc
44+
.withVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)
45+
.withVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
46+
)
47+
.build();
48+
49+
String json = mapper.writerWithDefaultPrettyPrinter()
50+
.writeValueAsString(new MyIllegalArgumentException());
51+
//System.err.println("JSON: " + json);
52+
assertNotNull(json);
53+
}
54+
}

0 commit comments

Comments
 (0)