Skip to content

Commit b70b520

Browse files
authored
Fix #4184: setCurrentValue() for empty POJO called at wrong time (#4186)
1 parent b332a42 commit b70b520

File tree

3 files changed

+106
-2
lines changed

3 files changed

+106
-2
lines changed

release-notes/VERSION-2.x

+6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ Project: jackson-databind
44
=== Releases ===
55
------------------------------------------------------------------------
66

7+
(not yet released)
8+
9+
#4184: `BeanDeserializer` updates `currentValue` incorrectly when
10+
deserialising empty Object
11+
(reported by @nocny-x)
12+
713
2.16.0-rc1 (20-Oct-2023)
814

915
#2502: Add a way to configure caches Jackson uses

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -296,9 +296,10 @@ private final Object vanillaDeserialize(JsonParser p,
296296
throws IOException
297297
{
298298
final Object bean = _valueInstantiator.createUsingDefault(ctxt);
299-
// [databind#631]: Assign current value, to be accessible by custom serializers
300-
p.setCurrentValue(bean);
301299
if (p.hasTokenId(JsonTokenId.ID_FIELD_NAME)) {
300+
// [databind#631]: Assign current value, to be accessible by custom serializers
301+
// [databind#4184]: but only if we have at least one property
302+
p.setCurrentValue(bean);
302303
String propName = p.currentName();
303304
do {
304305
p.nextToken();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package com.fasterxml.jackson.databind.ser.filter;
2+
3+
import java.io.IOException;
4+
5+
import com.fasterxml.jackson.core.*;
6+
7+
import com.fasterxml.jackson.databind.*;
8+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
9+
10+
// [databind#4184]
11+
public class CurrentValueDeser4184Test extends BaseMapTest
12+
{
13+
static class User {
14+
public Role role;
15+
public UserType type;
16+
}
17+
18+
static class Role {
19+
public String name;
20+
}
21+
22+
@JsonDeserialize(using = UserTypeDeserializer.class)
23+
enum UserType {
24+
ADMIN(1),
25+
USER(2);
26+
27+
final int value;
28+
29+
UserType(int value) {
30+
this.value = value;
31+
}
32+
33+
public Integer getValue() {
34+
return this.value;
35+
}
36+
37+
public String getName() {
38+
return this.name();
39+
}
40+
}
41+
42+
static class UserTypeDeserializer extends JsonDeserializer<UserType> {
43+
@Override
44+
public UserType deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
45+
Object currentValue;
46+
if (p.currentToken().isStructStart()) {
47+
currentValue = p.getParsingContext().getParent().getCurrentValue();
48+
} else {
49+
currentValue = p.getParsingContext().getCurrentValue();
50+
}
51+
if (null == currentValue) {
52+
ctxt.reportInputMismatch(UserType.class, "No currentValue() available");
53+
}
54+
if (!(currentValue instanceof User)) {
55+
ctxt.reportInputMismatch(UserType.class, "currentValue() of wrong type, not User but: "
56+
+currentValue.getClass().getName());
57+
}
58+
JsonNode node = ctxt.readTree(p);
59+
int value = node.path("value").asInt(-1);
60+
switch (value) {
61+
case 1:
62+
return UserType.ADMIN;
63+
case 2:
64+
return UserType.USER;
65+
}
66+
throw new IllegalArgumentException("Bad value: "+value);
67+
}
68+
}
69+
70+
/*
71+
/**********************************************************************
72+
/* Test methods
73+
/**********************************************************************
74+
*/
75+
76+
private final ObjectMapper MAPPER = newJsonMapper();
77+
78+
// [databind#4184]
79+
public void testCurrentValue4184FullPojo() throws Exception
80+
{
81+
String json = "{\"role\": {\"name\": \"Manager\"}, \"type\": {\"value\":1}}";
82+
83+
User user = MAPPER.readValue(json, User.class);
84+
assertNotNull(user);
85+
assertEquals(UserType.ADMIN, user.type);
86+
}
87+
88+
// [databind#4184]
89+
public void testCurrentValue4184EmptyPojo() throws Exception
90+
{
91+
String json = "{\"role\": {}, \"type\": {\"value\":1}}";
92+
93+
User user = MAPPER.readValue(json, User.class);
94+
assertNotNull(user);
95+
assertEquals(UserType.ADMIN, user.type);
96+
}
97+
}

0 commit comments

Comments
 (0)