Skip to content

Commit f26f9e3

Browse files
authored
Ignore Records' immutable fields in BeanDeserializerFactory instead of ignoring it in POJOPropertiesCollector, to preserve any annotation info the fields may be carrying. (#4627)
1 parent 8a21a83 commit f26f9e3

File tree

7 files changed

+79
-18
lines changed

7 files changed

+79
-18
lines changed

release-notes/CREDITS-2.x

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Co-Authors (with only partial listings below):
1010

1111
* Joo Hyuk Kim (JooHyukKim@github)
1212
* PJ Fanning (pjfanning@github)
13+
* Sim Yih Tsern (yihtsern@github)
1314

1415
----------------------------------------------------------------------------
1516

@@ -1624,9 +1625,9 @@ Sim Yih Tsern (yihtsern@github)
16241625
* Contributed fix for #3897: 2.15.0 breaks deserialization when POJO/Record only has a
16251626
single field and is marked `Access.WRITE_ONLY`
16261627
(2.15.1)
1627-
* Contributed fux fix #3968: Records with additional constructors failed to deserialize
1628+
* Contributed fix fix #3968: Records with additional constructors failed to deserialize
16281629
(2.15.3)
1629-
1630+
... and many more
16301631
16311632
Ajay Siwach (Siwach16@github)
16321633
* Contributed #3637: Add enum features into `@JsonFormat.Feature`

release-notes/VERSION-2.x

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ Project: jackson-databind
5757
(reported by Eduard G)
5858
#4617: Record property serialization order not preserved
5959
(reported by @GeorgiPetkov)
60+
#4626: `@JsonIgnore` on Record property ignored for deserialization, if there
61+
is getter override
62+
(contributed by @yihtserns)
63+
#4630: `@JsonIncludeProperties`, `@JsonIgnoreProperties` ignored when serializing Records,
64+
if there is getter override
65+
(contributed by @yihtserns)
6066

6167
2.17.2 (05-Jul-2024)
6268

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -977,8 +977,14 @@ protected SettableBeanProperty constructSettableProperty(DeserializationContext
977977
beanDesc.getClassAnnotations(), (AnnotatedMethod) mutator);
978978
} else {
979979
// 08-Sep-2016, tatu: wonder if we should verify it is `AnnotatedField` to be safe?
980-
prop = new FieldProperty(propDef, type, typeDeser,
981-
beanDesc.getClassAnnotations(), (AnnotatedField) mutator);
980+
AnnotatedField field = (AnnotatedField) mutator;
981+
// [databind#3736] Pointless to create a SettableBeanProperty for an immutable field
982+
// Records' fields can't mutated via reflection (JDK-8247517)
983+
// (also see [databind#4626]
984+
if (beanDesc.isRecordType()) {
985+
return null;
986+
}
987+
prop = new FieldProperty(propDef, type, typeDeser, beanDesc.getClassAnnotations(), field);
982988
}
983989
JsonDeserializer<?> deser = findDeserializerFromAnnotation(ctxt, mutator);
984990
if (deser == null) {

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

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -434,13 +434,7 @@ protected void collectAll()
434434
// First: gather basic accessors
435435
LinkedHashMap<String, POJOPropertyBuilder> props = new LinkedHashMap<String, POJOPropertyBuilder>();
436436

437-
// 15-Jan-2023, tatu: [databind#3736] Let's avoid detecting fields of Records
438-
// altogether (unless we find a good reason to detect them)
439-
// 17-Apr-2023: Need Records' fields for serialization for cases
440-
// like [databind#3628], [databind#3895] and [databind#3992]
441-
if (!isRecordType() || _forSerialization) {
442-
_addFields(props); // note: populates _fieldRenameMappings
443-
}
437+
_addFields(props); // note: populates _fieldRenameMappings
444438
_addMethods(props);
445439
// 25-Jan-2016, tatu: Avoid introspecting (constructor-)creators for non-static
446440
// inner classes, see [databind#1502]
@@ -1301,10 +1295,7 @@ protected void _removeUnwantedProperties(Map<String, POJOPropertyBuilder> props)
13011295
*/
13021296
protected void _removeUnwantedAccessor(Map<String, POJOPropertyBuilder> props)
13031297
{
1304-
// 15-Jan-2023, tatu: Avoid pulling in mutators for Records; Fields mostly
1305-
// since there should not be setters.
1306-
final boolean inferMutators = !isRecordType()
1307-
&& _config.isEnabled(MapperFeature.INFER_PROPERTY_MUTATORS);
1298+
final boolean inferMutators = _config.isEnabled(MapperFeature.INFER_PROPERTY_MUTATORS);
13081299
Iterator<POJOPropertyBuilder> it = props.values().iterator();
13091300

13101301
while (it.hasNext()) {

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,14 @@ public void testHelloRecord() throws Exception {
5050
HelloRecord result = MAPPER.readValue(json, HelloRecord.class);
5151
assertNotNull(result);
5252
}
53+
54+
// [databind#4626]
55+
@Test
56+
public void testDeserialize() throws Exception {
57+
HelloRecord expected = new HelloRecord("hello", null);
58+
59+
assertEquals(expected, MAPPER.readValue(a2q("{'text':'hello'}"), HelloRecord.class));
60+
assertEquals(expected, MAPPER.readValue(a2q("{'text':'hello','hidden':null}"), HelloRecord.class));
61+
assertEquals(expected, MAPPER.readValue(a2q("{'text':'hello','hidden':{'all': []}}"), HelloRecord.class));
62+
}
5363
}

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,11 @@ public void testSerializeJsonIgnoreAccessorRecord() throws Exception {
8181

8282
@Test
8383
public void testDeserializeJsonIgnoreAccessorRecord() throws Exception {
84-
RecordWithIgnoreAccessor value = MAPPER.readValue("{\"id\":123,\"name\":\"Bob\"}",
85-
RecordWithIgnoreAccessor.class);
86-
assertEquals(new RecordWithIgnoreAccessor(123, null), value);
84+
RecordWithIgnoreAccessor expected = new RecordWithIgnoreAccessor(123, null);
85+
86+
assertEquals(expected, MAPPER.readValue("{\"id\":123}", RecordWithIgnoreAccessor.class));
87+
assertEquals(expected, MAPPER.readValue("{\"id\":123,\"name\":null}", RecordWithIgnoreAccessor.class));
88+
assertEquals(expected, MAPPER.readValue("{\"id\":123,\"name\":\"Bob\"}", RecordWithIgnoreAccessor.class));
8789
}
8890

8991
/*
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.fasterxml.jackson.databind.records;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4+
import com.fasterxml.jackson.annotation.JsonIncludeProperties;
5+
import com.fasterxml.jackson.databind.ObjectMapper;
6+
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
7+
import org.junit.jupiter.api.Test;
8+
9+
import static org.junit.jupiter.api.Assertions.assertEquals;
10+
11+
public class RecordWithOverriddenAccessorTest extends DatabindTestUtil {
12+
13+
record Id2Name(int id, String name) {
14+
}
15+
16+
record RecordWithJsonIncludeProperties(@JsonIncludeProperties("id") Id2Name child) {
17+
@Override
18+
public Id2Name child() {
19+
return child;
20+
}
21+
}
22+
23+
record RecordWithJsonIgnoreProperties(@JsonIgnoreProperties("name") Id2Name child) {
24+
@Override
25+
public Id2Name child() {
26+
return child;
27+
}
28+
}
29+
30+
private final ObjectMapper MAPPER = newJsonMapper();
31+
32+
// [databind#4630]
33+
@Test
34+
public void testSerializeJsonIncludeProperties() throws Exception {
35+
String json = MAPPER.writeValueAsString(new RecordWithJsonIncludeProperties(new Id2Name(123, "Bob")));
36+
assertEquals(a2q("{'child':{'id':123}}"), json);
37+
}
38+
39+
// [databind#4630]
40+
@Test
41+
public void testSerializeJsonIgnoreProperties() throws Exception {
42+
String json = MAPPER.writeValueAsString(new RecordWithJsonIgnoreProperties(new Id2Name(123, "Bob")));
43+
assertEquals(a2q("{'child':{'id':123}}"), json);
44+
}
45+
}

0 commit comments

Comments
 (0)