From 47724b3cbac77ccf24d10c9e0c7095d8a52d5251 Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Mon, 12 Jun 2023 11:38:28 +0200 Subject: [PATCH] Fix regression in PUT handling for empty nested documents. The fix for #2174 introduced a bug for our PUT handling of nested documents in case the target object's field value is null as it would only apply the nested value if all Optionals were present. This is, of course not the case. Fixes #2264. --- .../rest/webmvc/json/DomainObjectReader.java | 6 ++++-- .../json/DomainObjectReaderUnitTests.java | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/DomainObjectReader.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/DomainObjectReader.java index a26e5d259..82c03deab 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/DomainObjectReader.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/DomainObjectReader.java @@ -40,7 +40,6 @@ import org.springframework.data.mapping.model.ConvertingPropertyAccessor; import org.springframework.data.rest.webmvc.mapping.Associations; import org.springframework.data.rest.webmvc.util.InputStreamHttpInputMessage; import org.springframework.data.util.ClassTypeInformation; -import org.springframework.data.util.Optionals; import org.springframework.data.util.TypeInformation; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.lang.Nullable; @@ -685,7 +684,10 @@ public class DomainObjectReader { } else if (property.isCollectionLike()) { result = mergeCollections(property, sourceValue, targetValue, mapper); } else if (property.isEntity()) { - result = Optionals.mapIfAllPresent(sourceValue, targetValue, (l, r) -> mergeForPut(l, r, mapper)); + + result = targetValue.isEmpty() + ? sourceValue + : targetValue.flatMap(t -> sourceValue.map(s -> mergeForPut(s, t, mapper))); } else { result = sourceValue; } diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/DomainObjectReaderUnitTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/DomainObjectReaderUnitTests.java index cfcf313fa..6ec07d9d6 100755 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/DomainObjectReaderUnitTests.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/DomainObjectReaderUnitTests.java @@ -662,6 +662,26 @@ class DomainObjectReaderUnitTests { assertThat(result.longs).isEqualTo(Arrays.asList(1L, 2L)); } + @Test // GH-2264 + void nestedEntitiesAreCreatedWhenMissingForPut() throws Exception { + + Outer outer = new Outer(); + outer.name = "outer name"; + outer.prop = "something"; + + JsonNode node = new ObjectMapper().readTree( + "{ \"inner\" : { \"name\" : \"new inner name\", \"readOnly\" : \"readonly value\", \"hidden\" : \"hidden value\" } }"); + + Outer result = reader.readPut((ObjectNode) node, outer, new ObjectMapper()); + + assertThat(result).isSameAs(outer); + assertThat(result.inner).isNotNull(); + assertThat(result.inner.prop).isNull(); + assertThat(result.inner.name).isEqualTo("new inner name"); + assertThat(result.inner.readOnly).isNull(); + assertThat(result.inner.hidden).isNull(); + } + @SuppressWarnings("unchecked") private static T as(Object source, Class type) {