Skip to content

Commit

Permalink
Fix #3992: avoid too early/eager removal of accessors (#4053)
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder authored Jul 24, 2023
1 parent daa0361 commit 035fba3
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 8 deletions.
2 changes: 2 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ Project: jackson-databind
(contributed by Joo-Hyuk K)
#3965: Add `JsonNodeFeature.WRITE_PROPERTIES_SORTED` for sorting `ObjectNode` properties
on serialization
#3992: `@JsonIgnore` on Record property ignored if there is getter override
(reported by @ennishol)
#4008: Optimize `ObjectNode` findValue(s) and findParent(s) fast paths
(contributed by David S)
#4009: Locale "" is deserialised as `null` if `ACCEPT_EMPTY_STRING_AS_NULL_OBJECT`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -976,12 +976,15 @@ protected void _removeUnwantedProperties(Map<String, POJOPropertyBuilder> props)
// Otherwise, check ignorals
if (prop.anyIgnorals()) {
// Special handling for Records, as they do not have mutators so relying on constructors
// with (mostly) implicitly-named parameters...
if (isRecordType()) {
// ...so can only remove ignored field and/or accessors, not constructor parameters that are needed
// for instantiation...
prop.removeIgnored();
// ...which will then be ignored (the incoming property value) during deserialization
// with (mostly) implicitly-named parameters...
// 20-Jul-2023, tatu: This can be harmful, see f.ex [databind#3992] so
// only use special handling for deserialization

if (isRecordType() && !_forSerialization) {
// ...so can only remove ignored field and/or accessors, not constructor parameters that are needed
// for instantiation...
prop.removeIgnored();
// ...which will then be ignored (the incoming property value) during deserialization
_collectIgnorals(prop.getName());
continue;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.fasterxml.jackson.databind.records;

import java.util.*;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.BaseMapTest;
import com.fasterxml.jackson.databind.ObjectMapper;

public class RecordWithIgnoreOverride3992Test extends BaseMapTest
{
// [databind#3992]
public record HelloRecord(String text, @JsonIgnore Recursion hidden) {
// Before fix: works if this override is removed
// After fix: works either way
@Override
public Recursion hidden() {
return hidden;
}
}

static class Recursion {
public List<Recursion> all = new ArrayList<>();

void add(Recursion recursion) {
all.add(recursion);
}
}

private final ObjectMapper MAPPER = newJsonMapper();

/*
/**********************************************************************
/* Test methods
/**********************************************************************
*/

// [databind#3992]
public void testHelloRecord() throws Exception {
Recursion beanWithRecursion = new Recursion();
beanWithRecursion.add(beanWithRecursion);
String json = MAPPER.writer()
.writeValueAsString(new HelloRecord("hello", beanWithRecursion));
assertEquals(a2q("{'text':'hello'}"), json);

// Let's check deserialization works too, just in case.
HelloRecord result = MAPPER.readValue(json, HelloRecord.class);
assertNotNull(result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ public void testSerializeJsonIgnoreRecord() throws Exception {
}

public void testDeserializeJsonIgnoreRecord() throws Exception {
RecordWithIgnore value = MAPPER.readValue("{\"id\":123,\"name\":\"Bob\"}", RecordWithIgnore.class);
RecordWithIgnore value = MAPPER.readValue("{\"id\":123,\"name\":\"Bob\"}",
RecordWithIgnore.class);
assertEquals(new RecordWithIgnore(123, null), value);
}

Expand Down Expand Up @@ -71,7 +72,8 @@ public void testSerializeJsonIgnoreAccessorRecord() throws Exception {
}

public void testDeserializeJsonIgnoreAccessorRecord() throws Exception {
RecordWithIgnoreAccessor value = MAPPER.readValue("{\"id\":123,\"name\":\"Bob\"}", RecordWithIgnoreAccessor.class);
RecordWithIgnoreAccessor value = MAPPER.readValue("{\"id\":123,\"name\":\"Bob\"}",
RecordWithIgnoreAccessor.class);
assertEquals(new RecordWithIgnoreAccessor(123, null), value);
}

Expand Down

0 comments on commit 035fba3

Please sign in to comment.