Skip to content

Commit f960f7c

Browse files
authored
Fix #4690, duplicated property to single-property Record (#5444)
1 parent df68426 commit f960f7c

File tree

6 files changed

+88
-90
lines changed

6 files changed

+88
-90
lines changed

release-notes/VERSION

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,17 @@ Versions: 3.x (for earlier see VERSION-2.x)
1313
(contributed by @sri-adarsh-kumar)
1414
#1980: Add method `remove(JsonPointer)` in `ContainerNode`
1515
(fix by @cowtowncoder, w/ Claude code)
16+
#3964: Deserialization issue: MismatchedInputException, Bean not
17+
yet resolved
18+
(reported by @detomarco)
1619
#4629: `@JsonIncludeProperties` and `@JsonIgnoreProperties` ignored when
1720
deserializing Records
1821
(reported by Sim Y-T)
1922
(fix contributed by @JacksonJang)
23+
#4690: InvalidDefinitionException "No fallback setter/field defined for
24+
creator property" when deserializing JSON with dup property to single-property Record
25+
(reported by @sseelmann)
26+
(fix contributed by @JacksonJang)
2027
#5350: Add `DeserializationFeature.USE_NULL_FOR_MISSING_REFERENCE_VALUES` for
2128
selecting `null` vs "empty/absent" value when deserializing missing `Optional` value
2229
#5361: Fix Maven SBOM publishing (worked in 3.0.0-rc4 but not in rc5 or later)

src/main/java/tools/jackson/databind/deser/bean/BeanDeserializer.java

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,6 @@ protected Object _deserializeUsingPropertyBased(final JsonParser p, final Deseri
586586

587587
// Creator property?
588588
if (creatorProp != null) {
589-
Object value;
590589
if ((activeView != null) && !creatorProp.visibleInView(activeView)) {
591590
p.skipChildren();
592591
continue;
@@ -597,34 +596,11 @@ protected Object _deserializeUsingPropertyBased(final JsonParser p, final Deseri
597596
p.skipChildren();
598597
continue;
599598
}
600-
value = _deserializeWithErrorWrapping(p, ctxt, creatorProp);
599+
Object value = _deserializeWithErrorWrapping(p, ctxt, creatorProp);
601600
// Last creator property to set?
602-
if (buffer.assignParameter(creatorProp, value)) {
603-
p.nextToken(); // to move to following PROPERTY_NAME/END_OBJECT
604-
Object bean;
605-
try {
606-
bean = creator.build(ctxt, buffer);
607-
} catch (Exception e) {
608-
bean = wrapInstantiationProblem(ctxt, e);
609-
}
610-
// [databind#631]: Assign current value, to be accessible by custom serializers
611-
p.assignCurrentValue(bean);
612-
// [databind#4938] Since 2.19, allow returning `null` from creator,
613-
// but if so, need to skip all possibly relevant content
614-
if (bean == null) {
615-
_handleNullFromPropsBasedCreator(p, ctxt, unknown, referrings);
616-
return null;
617-
}
618-
619-
if (bean.getClass() != _beanType.getRawClass()) {
620-
return handlePolymorphic(p, ctxt, bean, unknown);
621-
}
622-
if (unknown != null) { // nope, just extra unknown stuff...
623-
bean = handleUnknownProperties(ctxt, bean, unknown);
624-
}
625-
// or just clean?
626-
return deserialize(p, ctxt, bean);
627-
}
601+
// [databind#4690] cannot quit early as optimization any more
602+
// if (buffer.assignParameter(creatorProp, value)) { ... build ... }
603+
buffer.assignParameter(creatorProp, value);
628604
continue;
629605
}
630606
// regular property? needs buffering

src/test/java/tools/jackson/databind/deser/filter/IgnoreUnknownPropertyUsingPropertyBasedTest.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ static class UnwrappedChild {
6464

6565
@Test
6666
public void testAnySetterWithFailOnUnknownDisabled() throws Exception {
67-
IgnoreUnknownAnySetter value = MAPPER.readValue("{\"a\":1, \"b\":2, \"x\":3, \"y\": 4}", IgnoreUnknownAnySetter.class);
67+
IgnoreUnknownAnySetter value = MAPPER.readValue(
68+
"{\"a\":1, \"b\":2, \"x\":3, \"y\": 4}", IgnoreUnknownAnySetter.class);
6869
assertNotNull(value);
6970
assertEquals(1, value.a);
7071
assertEquals(2, value.b);
@@ -75,12 +76,12 @@ public void testAnySetterWithFailOnUnknownDisabled() throws Exception {
7576

7677
@Test
7778
public void testUnwrappedWithFailOnUnknownDisabled() throws Exception {
78-
IgnoreUnknownUnwrapped value = MAPPER.readValue("{\"a\":1, \"b\": 2, \"x\":3, \"y\":4}", IgnoreUnknownUnwrapped.class);
79+
IgnoreUnknownUnwrapped value = MAPPER.readValue(
80+
"{\"a\":1, \"b\": 2, \"x\":3, \"y\":4}", IgnoreUnknownUnwrapped.class);
7981
assertNotNull(value);
8082
assertEquals(1, value.a);
8183
assertEquals(2, value.b);
8284
assertEquals(3, value.child.x);
8385
assertEquals(4, value.child.y);
8486
}
85-
8687
}

src/test/java/tools/jackson/databind/tofix/JsonIdentityInfoAndBackReferences3964Test.java renamed to src/test/java/tools/jackson/databind/objectid/JsonIdentityInfoAndBackReferences3964Test.java

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package tools.jackson.databind.tofix;
1+
package tools.jackson.databind.objectid;
22

33
import java.util.List;
44

@@ -8,15 +8,13 @@
88

99
import tools.jackson.databind.DeserializationFeature;
1010
import tools.jackson.databind.ObjectMapper;
11-
import tools.jackson.databind.exc.MismatchedInputException;
1211
import tools.jackson.databind.testutil.DatabindTestUtil;
13-
import tools.jackson.databind.testutil.failure.JacksonTestFailureExpected;
1412

1513
import static org.junit.jupiter.api.Assertions.assertEquals;
16-
import static org.junit.jupiter.api.Assertions.fail;
1714

1815
// [databind#3964] MismatchedInputException, Bean not yet resolved
19-
class JsonIdentityInfoAndBackReferences3964Test extends DatabindTestUtil {
16+
class JsonIdentityInfoAndBackReferences3964Test extends DatabindTestUtil
17+
{
2018
/**
2119
* Fails : Original test
2220
*/
@@ -206,9 +204,8 @@ public static class Shrimp {
206204
.enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).build();
207205

208206
/**
209-
* Fails : Original test
207+
* Original test: used to fail
210208
*/
211-
@JacksonTestFailureExpected
212209
@Test
213210
void original() throws Exception {
214211
String json = "{" +
@@ -227,21 +224,14 @@ void original() throws Exception {
227224
" ]\n" +
228225
" }";
229226

230-
try {
231-
Tree tree = MAPPER.readValue(json, Tree.class);
232-
// should reach here and pass... but throws Exception and fails
233-
assertEquals(tree, tree.fruits.get(0).tree);
234-
} catch (MismatchedInputException e) {
235-
verifyException(e, "Cannot resolve ObjectId forward reference using property 'animal'");
236-
verifyException(e, "Bean not yet resolved");
237-
fail("Should not reach");
238-
}
227+
Tree tree = MAPPER.readValue(json, Tree.class);
228+
// should reach here and pass... but throws Exception and fails
229+
assertEquals(tree, tree.fruits.get(0).tree);
239230
}
240231

241232
/**
242-
* Fails : Lean version that fails and Without getters and setters
233+
* Lean version that used to fail, and Without getters and setters
243234
*/
244-
@JacksonTestFailureExpected
245235
@Test
246236
void leanWithoutGetterAndSetters() throws Exception {
247237
String json = a2q("{" +
@@ -260,15 +250,9 @@ void leanWithoutGetterAndSetters() throws Exception {
260250
" ]" +
261251
" }");
262252

263-
try {
264-
Animal animal = MAPPER.readValue(json, Animal.class);
265-
// should reach here and pass... but throws Exception and fails
266-
assertEquals(animal, animal.cats.get(0).animal);
267-
} catch (MismatchedInputException e) {
268-
verifyException(e, "Cannot resolve ObjectId forward reference using property 'animal'");
269-
verifyException(e, "Bean not yet resolved");
270-
fail("Should not reach");
271-
}
253+
Animal animal = MAPPER.readValue(json, Animal.class);
254+
// should reach here and pass... but throws Exception and fails
255+
assertEquals(animal, animal.cats.get(0).animal);
272256
}
273257

274258
/**
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package tools.jackson.databind.records;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import com.fasterxml.jackson.annotation.JsonCreator;
6+
7+
import tools.jackson.databind.ObjectMapper;
8+
import tools.jackson.databind.testutil.DatabindTestUtil;
9+
10+
import static org.junit.jupiter.api.Assertions.assertEquals;
11+
import static org.junit.jupiter.api.Assertions.assertNotNull;
12+
13+
// [databind#4690] InvalidDefinitionException "No fallback setter/field defined for creator property"
14+
// when deserializing JSON with duplicated property to single-property Record
15+
public class DuplicatePropertyDeserializationRecord4690Test
16+
extends DatabindTestUtil
17+
{
18+
record MyRecord(String first) { }
19+
20+
static class MyPojo {
21+
private String first;
22+
23+
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
24+
MyPojo(String first) { this.first = first; }
25+
26+
public void setFirst(String first) {
27+
this.first = first;
28+
}
29+
30+
public String getFirst() {
31+
return first;
32+
}
33+
}
34+
35+
private final ObjectMapper mapper = newJsonMapper();
36+
37+
@Test
38+
void testDuplicatePropertyDeserialization() throws Exception {
39+
final String json = a2q("{'first':'value','first':'value2'}");
40+
41+
MyRecord result = mapper.readValue(json, MyRecord.class);
42+
43+
assertNotNull(result);
44+
assertEquals("value2", result.first());
45+
}
46+
47+
@Test
48+
void testDuplicatePropertyDeserialization2() throws Exception {
49+
final String json = a2q("{'first':'value','second':'test1','first':'value2'}");
50+
51+
MyRecord result = mapper.readValue(json, MyRecord.class);
52+
assertEquals("value2", result.first());
53+
}
54+
55+
@Test
56+
void testDuplicatePropertyClassDeserialization() throws Exception {
57+
final String json = a2q("{'first':'value','second':'test1','first':'value2'}");
58+
59+
MyPojo result = mapper.readValue(json, MyPojo.class);
60+
assertEquals("value2", result.getFirst());
61+
}
62+
}

src/test/java/tools/jackson/databind/records/tofix/DuplicatePropertyDeserializationRecord4690Test.java

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)