From 63d9d5d6a1135ef5839f3953167ed6c2ed8131e5 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Wed, 3 Dec 2025 18:48:26 -0800 Subject: [PATCH] Fix #5115 --- release-notes/CREDITS | 10 ++++- release-notes/VERSION | 3 ++ .../introspect/POJOPropertiesCollector.java | 39 +++++++++++-------- .../{tofix => }/RecordUnwrapped5115Test.java | 5 +-- 4 files changed, 36 insertions(+), 21 deletions(-) rename src/test/java/tools/jackson/databind/records/{tofix => }/RecordUnwrapped5115Test.java (93%) diff --git a/release-notes/CREDITS b/release-notes/CREDITS index 3699ac0711..f74eac913f 100644 --- a/release-notes/CREDITS +++ b/release-notes/CREDITS @@ -127,7 +127,15 @@ Oliver Drotbohm (@odrotbohm) * Contributed fix for #4629: `@JsonIncludeProperties` and `@JsonIgnoreProperties` ignored when deserializing Records [3.1.0] - + * Contributed fix for #5115: `@JsonUnwrapped` Record deserialization can't handle + name collision + [3.1.0] + +Viktor Szathmáry (@phraktle) + * Reported #5115: `@JsonUnwrapped` Record deserialization can't handle name collision + (reported by Viktor S) + [3.1.0] + Hélios Gilles (@RoiSoleil) * Contributed #5413: Add/support forward reference resolution for array values [3.1.0] diff --git a/release-notes/VERSION b/release-notes/VERSION index e088f48746..df98713858 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION @@ -24,6 +24,9 @@ Versions: 3.x (for earlier see VERSION-2.x) creator property" when deserializing JSON with dup property to single-property Record (reported by @sseelmann) (fix contributed by @JacksonJang) +#5115: `@JsonUnwrapped` Record deserialization can't handle name collision + (reported by Viktor S) + (fix contributed by @JacksonJang) #5184: `@JsonIgnore` on record method applied to record matching field at deserialization (reported by @emouty) diff --git a/src/main/java/tools/jackson/databind/introspect/POJOPropertiesCollector.java b/src/main/java/tools/jackson/databind/introspect/POJOPropertiesCollector.java index 523eaad865..25bf4967de 100644 --- a/src/main/java/tools/jackson/databind/introspect/POJOPropertiesCollector.java +++ b/src/main/java/tools/jackson/databind/introspect/POJOPropertiesCollector.java @@ -1054,33 +1054,38 @@ private void _addCreatorParams(Map props, final PropertyName explName = ctor.explicitName(i); PropertyName implName = ctor.implicitName(i); final boolean hasExplicit = (explName != null); - final POJOPropertyBuilder prop; - - // neither implicit nor explicit name? - if (!hasExplicit && (implName == null)) { - boolean isUnwrapping = _annotationIntrospector.findUnwrappingNameTransformer(_config, param) != null; + final boolean hasImplicit = (implName != null); - if (isUnwrapping) { + // First: check "Unwrapped" unless explicit name + if (!hasExplicit) { + var unwrapper = _annotationIntrospector.findUnwrappingNameTransformer(_config, param); + if (unwrapper != null) { // If unwrapping, can use regardless of name; we will use a placeholder name // anyway to try to avoid name conflicts. PropertyName name = UnwrappedPropertyHandler.creatorParamName(param.getIndex()); - prop = _property(props, name); + final POJOPropertyBuilder prop = _property(props, name); prop.addCtor(param, name, false, true, false); - } else { + creatorProps.add(prop); + continue; + } + if (!hasImplicit) { // Without name, cannot make use of this creator parameter -- may or may not // be a problem, verified at a later point. - prop = null; + creatorProps.add(null); + continue; } + } + + // 27-Dec-2019, tatu: [databind#2527] may need to rename according to field + final POJOPropertyBuilder prop; + if (hasImplicit) { + String n = _checkRenameByField(implName.getSimpleName()); + implName = PropertyName.construct(n); + prop = _property(props, implName); } else { - // 27-Dec-2019, tatu: [databind#2527] may need to rename according to field - if (implName != null) { - String n = _checkRenameByField(implName.getSimpleName()); - implName = PropertyName.construct(n); - } - prop = (implName == null) - ? _property(props, explName) : _property(props, implName); - prop.addCtor(param, hasExplicit ? explName : implName, hasExplicit, true, false); + prop = _property(props, explName); } + prop.addCtor(param, hasExplicit ? explName : implName, hasExplicit, true, false); creatorProps.add(prop); } ctor.assignPropertyDefs(creatorProps); diff --git a/src/test/java/tools/jackson/databind/records/tofix/RecordUnwrapped5115Test.java b/src/test/java/tools/jackson/databind/records/RecordUnwrapped5115Test.java similarity index 93% rename from src/test/java/tools/jackson/databind/records/tofix/RecordUnwrapped5115Test.java rename to src/test/java/tools/jackson/databind/records/RecordUnwrapped5115Test.java index 4c95b54d5f..b8ac42c30e 100644 --- a/src/test/java/tools/jackson/databind/records/tofix/RecordUnwrapped5115Test.java +++ b/src/test/java/tools/jackson/databind/records/RecordUnwrapped5115Test.java @@ -1,11 +1,11 @@ -package tools.jackson.databind.records.tofix; +package tools.jackson.databind.records; import org.junit.jupiter.api.Test; import com.fasterxml.jackson.annotation.JsonUnwrapped; + import tools.jackson.databind.ObjectMapper; import tools.jackson.databind.testutil.DatabindTestUtil; -import tools.jackson.databind.testutil.failure.JacksonTestFailureExpected; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -62,7 +62,6 @@ void unwrappedRecordShouldRoundTripPass() throws Exception assertEquals(input, output); } - @JacksonTestFailureExpected @Test void unwrappedRecordShouldRoundTrip() throws Exception {