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 4f8d64b7a22..9a1669a7543 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 00000000000..3c9b24d437c --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/deser/creators/DelegatingCreatorImplicitNames2543Test.java @@ -0,0 +1,66 @@ +package com.fasterxml.jackson.databind.deser.creators; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +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.assertThatNoException; + +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 p) { + if (p.getOwner() instanceof AnnotatedMethod m) { + if (requireNonNull(m.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() { + assertThatNoException() + .isThrownBy(() -> MAPPER.readValue(a2q("{'part1':'a','part2':'b'}"), Data.class)); + } + + @Test + public void testDelegatingDeserialization() { + assertThatNoException() + .isThrownBy(() -> MAPPER.readValue(a2q("'a b'"), Data.class)); + } +}