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 54e412e2a..a909617ad 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,6 +40,7 @@ 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; @@ -61,6 +62,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; * @author Craig Andrews * @author Mathias Düsterhöft * @author Thomas Mrozinski + * @author Lars Vierbergen * @since 2.2 */ public class DomainObjectReader { @@ -678,7 +680,7 @@ public class DomainObjectReader { } else if (property.isCollectionLike()) { result = mergeCollections(property, sourceValue, targetValue, mapper); } else if (property.isEntity()) { - result = mergeForPut(sourceValue, targetValue, mapper); + result = Optionals.mapIfAllPresent(sourceValue, targetValue, (l, r) -> mergeForPut(l, r, 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 b9ba41773..9eb0711cd 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 @@ -618,6 +618,33 @@ class DomainObjectReaderUnitTests { }); } + @Test // #2174 + void nestedEntitiesWithReadonlyFieldAreKeptForPut() throws Exception { + + Inner inner = new Inner(); + inner.name = "inner name"; + inner.prop = "something"; + inner.readOnly = "readonly value"; + inner.hidden = "hidden value"; + + Outer outer = new Outer(); + outer.prop = "else"; + outer.name = "outer name"; + outer.inner = inner; + + JsonNode node = new ObjectMapper().readTree("{ \"inner\" : { \"name\" : \"new inner name\" } }"); + + Outer result = reader.readPut((ObjectNode) node, outer, new ObjectMapper()); + + assertThat(result).isSameAs(outer); + assertThat(result.prop).isNull(); + assertThat(result.inner.prop).isNull(); + assertThat(result.inner.name).isEqualTo("new inner name"); + assertThat(result.inner.readOnly).isEqualTo("readonly value"); + assertThat(result.inner.hidden).isEqualTo("hidden value"); + assertThat(result.inner).isSameAs(inner); + } + @SuppressWarnings("unchecked") private static T as(Object source, Class type) { @@ -715,6 +742,8 @@ class DomainObjectReaderUnitTests { String name; String prop; + @JsonProperty(access = READ_ONLY) String readOnly; + @JsonIgnore String hidden; } @JsonAutoDetect(fieldVisibility = Visibility.ANY)