jackson-databind
jackson-databind copied to clipboard
`@JsonIgnore` on record method applied to record matching field at deserialization
Search before asking
- [x] I searched in the issues and found nothing similar.
Describe the bug
Since version 2.18.4 (probably since https://github.com/FasterXML/jackson-databind/issues/4628) behavior of annotation on methods of a records has changed.
before 2.18.4, If I had
public record TestData(
@JsonProperty("test_property")
String value) {
@JsonIgnore
public Optional<String> getValue() {
return Optional.ofNullable(value);
}
}
and serialized object
{ "test_property": "jackson" }
it would be deserialized to TestData("jackson")
Now since 2.18.4, the @JsonIgnore is applied to the value field even though getValue is not the record getter. This make TestData to be deserialized to TestData(null)
It seems that Jackson confuse the getValue() for the record getter value(). If I name my method something else than getX the @JsonIgnore is not applied to the field.
What make me think that its a bug is that an equivalent case with a class doesn't have the same behavior. If I have a class getter with @JsonIgnore the object mapper won't apply the ignore to the class field but only the method.
Version Information
2.18.4 and 2.19.0
Reproduction
package com.libon.jackson;
import static org.assertj.core.api.Assertions.assertThat;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
class JacksonTest {
private static final ObjectMapper MAPPER = new ObjectMapper().disable(FAIL_ON_UNKNOWN_PROPERTIES);
@Test
void should_deserialize_json_to_test_data() throws Exception {
String json = """
{"test_property":"test value"}
""";
var testData = MAPPER.readValue(json, JacksonTest.TestData.class);
assertThat(testData.value()).isEqualTo("test value");
}
@Test
void should_deserialize_json_to_test_data_class() throws Exception {
String json = """
{"test_property":"test value"}
""";
var testData = MAPPER.readValue(json, JacksonTest.TestDataClass.class);
assertThat(testData.getValue()).contains("test value");
}
@Test
void should_deserialize_json_to_test_data_alternate() throws Exception {
String json = """
{"test_property":"test value"}
""";
var testData = MAPPER.readValue(json, JacksonTest.TestDataAlternate.class);
assertThat(testData.value()).isEqualTo("test value");
}
@Test
void should_not_deserialize_wrong_json_model_to_test_data() throws Exception {
String json = """
{"value":"test value"}
""";
JacksonTest.TestData testData = MAPPER.readValue(json, JacksonTest.TestData.class);
assertThat(testData.value()).isNull();
}
public record TestData(
@JsonProperty("test_property")
String value) {
@JsonIgnore
public Optional<String> getValue() {
return Optional.ofNullable(value);
}
}
public record TestDataAlternate(
@JsonProperty("test_property")
String value) {
@JsonIgnore
public Optional<String> optionalValue() {
return Optional.ofNullable(value);
}
}
public static final class TestDataClass {
private final String value;
public TestDataClass(
@JsonProperty("test_property")
String value) {
this.value = value;
}
@JsonIgnore
public Optional<String> getValue() {
return Optional.ofNullable(value);
}
}
}
Expected behavior
The @JsonIgnore on a record method should not be applied to the record field especially when its not the field getter.
Additional context
No response