From 0bc2f5d0f6b307982390b78aa798e462cc926081 Mon Sep 17 00:00:00 2001 From: Kyrylo Merzlikin Date: Sun, 10 Mar 2024 15:01:00 +0200 Subject: [PATCH] Fix #2543: Skip delegating creator arguments when collecting properties --- .../introspect/POJOPropertiesCollector.java | 5 +- ...elegatingCreatorImplicitNames2543Test.java | 73 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/fasterxml/jackson/databind/deser/creators/DelegatingCreatorImplicitNames2543Test.java diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java index 4f8d64b7a2..9a1669a754 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java @@ -760,7 +760,10 @@ private void _addCreatorParam(Map props, // ...or is a Records canonical constructor boolean isCanonicalConstructor = recordComponentName != null; - if ((creatorMode == null || creatorMode == JsonCreator.Mode.DISABLED) && !isCanonicalConstructor) { + if ((creatorMode == null + || creatorMode == JsonCreator.Mode.DISABLED + || creatorMode == JsonCreator.Mode.DELEGATING) + && !isCanonicalConstructor) { return; } pn = PropertyName.construct(impl); diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/creators/DelegatingCreatorImplicitNames2543Test.java b/src/test/java/com/fasterxml/jackson/databind/deser/creators/DelegatingCreatorImplicitNames2543Test.java new file mode 100644 index 0000000000..d2f7d075fb --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/deser/creators/DelegatingCreatorImplicitNames2543Test.java @@ -0,0 +1,73 @@ +package com.fasterxml.jackson.databind.deser.creators; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.introspect.*; +import org.junit.Test; + +import static com.fasterxml.jackson.annotation.JsonCreator.Mode.DELEGATING; +import static com.fasterxml.jackson.annotation.JsonCreator.Mode.PROPERTIES; +import static com.fasterxml.jackson.databind.testutil.DatabindTestUtil.a2q; +import static java.util.Objects.requireNonNull; +import static org.assertj.core.api.Assertions.assertThat; + +public class DelegatingCreatorImplicitNames2543Test { + static class Data { + + final String part1; + final String part2; + + // this creator is considered a source of settable bean properties, + // used during deserialization + @JsonCreator(mode = PROPERTIES) + public Data(@JsonProperty("part1") String part1, + @JsonProperty("part2") String part2) { + this.part1 = part1; + this.part2 = part2; + } + + // no properties should be collected from this creator, + // even though it has an argument with an implicit name + @JsonCreator(mode = DELEGATING) + public static Data fromFullData(String fullData) { + String[] parts = fullData.split("\\s+", 2); + return new Data(parts[0], parts[1]); + } + } + + private static class DelegatingCreatorNamedArgumentIntrospector + extends JacksonAnnotationIntrospector { + public String findImplicitPropertyName(AnnotatedMember member) { + if (member instanceof AnnotatedParameter) { + AnnotatedWithParams owner = ((AnnotatedParameter) member).getOwner(); + if (owner instanceof AnnotatedMethod) { + AnnotatedMethod method = (AnnotatedMethod) owner; + if (requireNonNull(method.getAnnotation(JsonCreator.class)).mode() == DELEGATING) + return "fullData"; + } + } + return super.findImplicitPropertyName(member); + } + } + + private static final ObjectMapper MAPPER = new ObjectMapper() + .setAnnotationIntrospector(new DelegatingCreatorNamedArgumentIntrospector()); + + @Test + public void testDeserialization() throws JsonProcessingException { + Data data = MAPPER.readValue(a2q("{'part1':'a','part2':'b'}"), Data.class); + + assertThat(data.part1).isEqualTo("a"); + assertThat(data.part2).isEqualTo("b"); + } + + @Test + public void testDelegatingDeserialization() throws JsonProcessingException { + Data data = MAPPER.readValue(a2q("'a b'"), Data.class); + + assertThat(data.part1).isEqualTo("a"); + assertThat(data.part2).isEqualTo("b"); + } +}