Skip to content

Commit 7d187c9

Browse files
authored
fix subclassed exception deserialization (#4847)
1 parent c1d3ea7 commit 7d187c9

File tree

3 files changed

+76
-14
lines changed

3 files changed

+76
-14
lines changed

release-notes/VERSION-2.x

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ Project: jackson-databind
44
=== Releases ===
55
------------------------------------------------------------------------
66

7+
2.18.3 (not yet released)
8+
9+
#4827: Subclassed Throwable deserialization fails since v2.18.0 - no creator
10+
index for property 'cause'
11+
(fix by Joo-Hyuk K)
12+
713
2.18.2 (27-Nov-2024)
814

915
#4733: Wrong serialization of Type Ids for certain types of Enum values

src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerFactory.java

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -438,20 +438,27 @@ public JsonDeserializer<Object> buildThrowableDeserializer(DeserializationContex
438438
}
439439
AnnotatedMethod am = beanDesc.findMethod("initCause", INIT_CAUSE_PARAMS);
440440
if (am != null) { // should never be null
441-
// [databind#3497]: must consider possible PropertyNamingStrategy
442-
String name = "cause";
443-
PropertyNamingStrategy pts = config.getPropertyNamingStrategy();
444-
if (pts != null) {
445-
name = pts.nameForSetterMethod(config, am, "cause");
446-
}
447-
SimpleBeanPropertyDefinition propDef = SimpleBeanPropertyDefinition.construct(ctxt.getConfig(), am,
448-
new PropertyName(name));
449-
SettableBeanProperty prop = constructSettableProperty(ctxt, beanDesc, propDef,
450-
am.getParameterType(0));
451-
if (prop != null) {
452-
// 21-Aug-2011, tatus: We may actually have found 'cause' property
453-
// to set... but let's replace it just in case, otherwise can end up with odd errors.
454-
builder.addOrReplaceProperty(prop, true);
441+
SettableBeanProperty causeCreatorProp = builder.findProperty(PropertyName.construct("cause"));
442+
// [databind#4827] : Consider case where sub-classed `Exception` has `JsonCreator` with `cause` parameter
443+
if (causeCreatorProp instanceof CreatorProperty) {
444+
// Set fallback-setter as null, so `fixAccess()` does not happen during build
445+
((CreatorProperty) causeCreatorProp).setFallbackSetter(null);
446+
} else {
447+
// [databind#3497]: must consider possible PropertyNamingStrategy
448+
String name = "cause";
449+
PropertyNamingStrategy pts = config.getPropertyNamingStrategy();
450+
if (pts != null) {
451+
name = pts.nameForSetterMethod(config, am, "cause");
452+
}
453+
SimpleBeanPropertyDefinition propDef = SimpleBeanPropertyDefinition.construct(ctxt.getConfig(), am,
454+
new PropertyName(name));
455+
SettableBeanProperty prop = constructSettableProperty(ctxt, beanDesc, propDef,
456+
am.getParameterType(0));
457+
if (prop != null) {
458+
// 21-Aug-2011, tatus: We may actually have found 'cause' property
459+
// to set... but let's replace it just in case, otherwise can end up with odd errors.
460+
builder.addOrReplaceProperty(prop, true);
461+
}
455462
}
456463
}
457464
// update builder now that all information is in?
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.fasterxml.jackson.databind.exc;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import com.fasterxml.jackson.annotation.JsonCreator;
6+
import com.fasterxml.jackson.annotation.JsonProperty;
7+
import com.fasterxml.jackson.databind.DeserializationFeature;
8+
import com.fasterxml.jackson.databind.ObjectMapper;
9+
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
10+
11+
import static org.junit.jupiter.api.Assertions.assertEquals;
12+
13+
// [databind#4827] Subclassed Throwable deserialization fails since v2.18.0
14+
// no creator index for property 'cause'
15+
public class SubclassedThrowableDeserialization4827Test
16+
extends DatabindTestUtil
17+
{
18+
19+
public static class SubclassedExceptionJava extends Exception {
20+
@JsonCreator
21+
public SubclassedExceptionJava(
22+
@JsonProperty("message") String message,
23+
@JsonProperty("cause") Throwable cause
24+
) {
25+
super(message, cause);
26+
}
27+
}
28+
29+
private final ObjectMapper MAPPER = jsonMapperBuilder()
30+
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
31+
.build();
32+
33+
@Test
34+
public void testDeserialization()
35+
throws Exception
36+
{
37+
// Given input
38+
SubclassedExceptionJava input = new SubclassedExceptionJava(
39+
"Test Message", new RuntimeException("test runtime cause"));
40+
41+
// When serialize, then deserialize, round-trip
42+
String serialized = MAPPER.writeValueAsString(input);
43+
SubclassedExceptionJava deserialized = MAPPER.readValue(serialized, SubclassedExceptionJava.class);
44+
45+
// Contents are same
46+
assertEquals(input.getMessage(), deserialized.getMessage());
47+
assertEquals(input.getCause().getMessage(), deserialized.getCause().getMessage());
48+
}
49+
}

0 commit comments

Comments
 (0)