diff --git a/src/main/java/tools/jackson/databind/introspect/POJOPropertiesCollector.java b/src/main/java/tools/jackson/databind/introspect/POJOPropertiesCollector.java index 341f30d815..12a1f06426 100644 --- a/src/main/java/tools/jackson/databind/introspect/POJOPropertiesCollector.java +++ b/src/main/java/tools/jackson/databind/introspect/POJOPropertiesCollector.java @@ -1062,21 +1062,28 @@ private void _addCreatorParams(Map props, final boolean hasExplicit = (explName != null); final POJOPropertyBuilder prop; - // neither implicit nor explicit name? - if (!hasExplicit && (implName == null)) { - boolean isUnwrapping = _annotationIntrospector.findUnwrappingNameTransformer(_config, param) != null; - - if (isUnwrapping) { - // If unwrapping, can use regardless of name; we will use a placeholder name - // anyway to try to avoid name conflicts. + // [databind#5115] Resolve @JsonUnwrapped by checking the parameter first, then falling back to its field. + final String implNameStr = (implName != null) ? implName.getSimpleName() : null; + final POJOPropertyBuilder existingProp = (implNameStr != null) ? props.get(implNameStr) : null; + final AnnotatedField field = (existingProp != null) ? existingProp.getField() : null; + + // [databind#5115] Determine whether the creator parameter should be treated as unwrapped. + final boolean isUnwrapping = + _annotationIntrospector.findUnwrappingNameTransformer(_config, param) != null || + (field != null && _annotationIntrospector.findUnwrappingNameTransformer(_config, field) != null); + + if (isUnwrapping) { + // [databind#5115] Serialization: Reuse the existing property, Deserialization: Use a placeholder creator property + if (_forSerialization && existingProp != null) { + existingProp.addCtor(param, implName, hasExplicit, true, false); + prop = existingProp; + } else { PropertyName name = UnwrappedPropertyHandler.creatorParamName(param.getIndex()); prop = _property(props, name); - prop.addCtor(param, name, false, true, false); - } else { - // Without name, cannot make use of this creator parameter -- may or may not - // be a problem, verified at a later point. - prop = null; + prop.addCtor(param, name, hasExplicit, true, false); } + } else if (!hasExplicit && (implName == null)) { + prop = null; } else { // 27-Dec-2019, tatu: [databind#2527] may need to rename according to field if (implName != null) { 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..1b47059130 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,10 @@ -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 +61,6 @@ void unwrappedRecordShouldRoundTripPass() throws Exception assertEquals(input, output); } - @JacksonTestFailureExpected @Test void unwrappedRecordShouldRoundTrip() throws Exception {