Skip to content

Commit 31bfb13

Browse files
authored
Fixing records deserialization issue (#5094, parts of #4628) with read-access when json renamed to same property name (#5073)
1 parent 9269ee3 commit 31bfb13

File tree

7 files changed

+97
-73
lines changed

7 files changed

+97
-73
lines changed

release-notes/CREDITS-2.x

+5
Original file line numberDiff line numberDiff line change
@@ -1885,3 +1885,8 @@ Zhen Lin Low (@zhenlin-pay2)
18851885
* Reported, fixed #4920: Creator properties are ignored on abstract types
18861886
when collecting bean properties, breaking AsExternalTypeDeserializer
18871887
(2.18.3)
1888+
1889+
Fawzi Essam (@iifawz)
1890+
* Contributed fix for #5049: Duplicate creator property "b" (index 0 vs 1)
1891+
on simple java record
1892+
(2.18.3)

release-notes/VERSION-2.x

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

7+
2.18.4 (not yet released)
8+
9+
#5049: Duplicate creator property "b" (index 0 vs 1) on simple java record
10+
(reported by @richard-melvin)
11+
(fix contributed by Fawzi E)
12+
713
2.18.3 (28-Feb-2025)
814

915
#4444: The `KeyDeserializer` specified in the class with `@JsonDeserialize(keyUsing = ...)`
@@ -13,7 +19,7 @@ Project: jackson-databind
1319
index for property 'cause'
1420
(reported by @nilswieber)
1521
(fix by Joo-Hyuk K)
16-
#4844: Fix wrapped array hanlding wrt `null` by `StdDeserializer`
22+
#4844: Fix wrapped array handling wrt `null` by `StdDeserializer`
1723
(fix by Stanislav S)
1824
#4848: Avoid type pollution in `StringCollectionDeserializer`
1925
(contributed by Jonas K)

src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1798,7 +1798,7 @@ protected boolean _replaceCreatorProperty(List<POJOPropertyBuilder> creatorPrope
17981798
POJOPropertyBuilder prop)
17991799
{
18001800
final AnnotatedParameter ctorParam = prop.getConstructorParameter();
1801-
if (creatorProperties != null) {
1801+
if (creatorProperties != null && ctorParam != null) {
18021802
for (int i = 0, len = creatorProperties.size(); i < len; ++i) {
18031803
POJOPropertyBuilder cprop = creatorProperties.get(i);
18041804
if (cprop != null) {

src/test-jdk17/java/com/fasterxml/jackson/databind/records/RecordWithJsonIgnoreTest.java

-6
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,6 @@ public void testSerializeJsonIgnoreAndJsonPropertyRecord() throws Exception {
6161
assertEquals("{\"id\":123}", json);
6262
}
6363

64-
@Test
65-
public void testDeserializeJsonIgnoreAndJsonPropertyRecord() throws Exception {
66-
RecordWithIgnoreJsonProperty value = MAPPER.readValue("{\"id\":123,\"name\":\"Bob\"}", RecordWithIgnoreJsonProperty.class);
67-
assertEquals(new RecordWithIgnoreJsonProperty(123, "Bob"), value);
68-
}
69-
7064
/*
7165
/**********************************************************************
7266
/* Test methods, JsonIgnore accessor

src/test-jdk17/java/com/fasterxml/jackson/databind/records/RecordWithReadOnlyTest.java

+45-5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import org.junit.jupiter.api.Test;
88

99
import static org.junit.jupiter.api.Assertions.assertEquals;
10+
import static org.junit.jupiter.api.Assertions.assertNotNull;
11+
import static org.junit.jupiter.api.Assertions.assertNull;
1012

1113
public class RecordWithReadOnlyTest extends DatabindTestUtil {
1214

@@ -50,6 +52,27 @@ public RecordWithReadOnlyAllAndNoArgConstructor() {
5052
}
5153
}
5254

55+
56+
static class ReadOnly5049Pojo
57+
{
58+
protected String a, b;
59+
60+
ReadOnly5049Pojo(
61+
@JsonProperty(value = "a", access = JsonProperty.Access.READ_ONLY) String a,
62+
@JsonProperty(value = "b", access = JsonProperty.Access.READ_ONLY) String b) {
63+
this.a = a;
64+
this.b = b;
65+
}
66+
67+
public String getA() { return a; }
68+
public String getB() { return b; }
69+
}
70+
71+
record ReadOnly5049Record(
72+
@JsonProperty(value = "a", access = JsonProperty.Access.READ_ONLY) String a,
73+
@JsonProperty(value = "b", access = JsonProperty.Access.READ_ONLY) String b) {
74+
}
75+
5376
private final ObjectMapper MAPPER = newJsonMapper();
5477

5578
/*
@@ -82,14 +105,31 @@ public void testSerializeReadOnlyNamedProperty() throws Exception {
82105
assertEquals(a2q("{'id':123,'name':'Bob'}"), json);
83106
}
84107

85-
/**
86-
* Currently documents a bug where a property was NOT ignored during deserialization if given an explicit name.
87-
* Also reproducible in 2.14.x.
88-
*/
108+
89109
@Test
90110
public void testDeserializeReadOnlyNamedProperty() throws Exception {
91111
RecordWithReadOnlyNamedProperty value = MAPPER.readValue(a2q("{'id':123,'name':'Bob'}"), RecordWithReadOnlyNamedProperty.class);
92-
assertEquals(new RecordWithReadOnlyNamedProperty(123, "Bob"), value); // BUG: should be `null` instead of "Bob"
112+
assertEquals(new RecordWithReadOnlyNamedProperty(123, null), value);
113+
}
114+
115+
@Test
116+
void testRoundtripPOJO() throws Exception
117+
{
118+
String json = MAPPER.writeValueAsString(new ReadOnly5049Pojo("hello", "world"));
119+
ReadOnly5049Pojo pojo = MAPPER.readerFor(ReadOnly5049Pojo.class).readValue(json);
120+
assertNotNull(pojo);
121+
assertNull(pojo.a);
122+
assertNull(pojo.b);
123+
}
124+
125+
@Test
126+
void testRoundtripRecord() throws Exception
127+
{
128+
String json = MAPPER.writeValueAsString(new ReadOnly5049Record("hello", "world"));
129+
ReadOnly5049Record record = MAPPER.readValue(json, ReadOnly5049Record.class);
130+
assertNotNull(record);
131+
assertNull(record.a());
132+
assertNull(record.b());
93133
}
94134

95135
/*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.fasterxml.jackson.databind.tofix;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnore;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
import com.fasterxml.jackson.databind.ObjectMapper;
6+
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
7+
import com.fasterxml.jackson.databind.testutil.failure.JacksonTestFailureExpected;
8+
import org.junit.jupiter.api.Test;
9+
10+
import static org.junit.jupiter.api.Assertions.assertEquals;
11+
12+
// [databind#4628] @JsonIgnore is ignored with read access
13+
public class RecordWIthJsonIgnoreAndValue4628Test
14+
extends DatabindTestUtil {
15+
16+
record RecordWithIgnoreJsonProperty(int id, @JsonIgnore @JsonProperty("name") String name) {
17+
}
18+
19+
record RecordWithIgnoreJsonPropertyDifferentName(int id, @JsonIgnore @JsonProperty("name2") String name) {
20+
}
21+
22+
private final ObjectMapper MAPPER = newJsonMapper();
23+
24+
25+
// passing normally given different name is used
26+
@Test
27+
public void testDeserializeJsonIgnoreRecordWithDifferentName() throws Exception {
28+
RecordWithIgnoreJsonPropertyDifferentName value = MAPPER.readValue("{\"id\":123,\"name\":\"Bob\"}", RecordWithIgnoreJsonPropertyDifferentName.class);
29+
assertEquals(new RecordWithIgnoreJsonPropertyDifferentName(123, null), value);
30+
}
31+
32+
@Test
33+
@JacksonTestFailureExpected
34+
public void testDeserializeJsonIgnoreAndJsonPropertyRecord() throws Exception {
35+
RecordWithIgnoreJsonProperty value = MAPPER.readValue("{\"id\":123,\"name\":\"Bob\"}", RecordWithIgnoreJsonProperty.class);
36+
assertEquals(new RecordWithIgnoreJsonProperty(123, null), value); // should be null, actual "bob"
37+
}
38+
39+
}

src/test-jdk17/java/com/fasterxml/jackson/databind/tofix/RecordWithReadOnly5049Test.java

-60
This file was deleted.

0 commit comments

Comments
 (0)