Properly deep-merge nested documents on PUT.
This is needed to consider read-only properties within those objects as those would otherwise get overridden. Fixes: #2174
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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> T as(Object source, Class<T> type) {
|
||||
|
||||
@@ -715,6 +742,8 @@ class DomainObjectReaderUnitTests {
|
||||
|
||||
String name;
|
||||
String prop;
|
||||
@JsonProperty(access = READ_ONLY) String readOnly;
|
||||
@JsonIgnore String hidden;
|
||||
}
|
||||
|
||||
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
|
||||
|
||||
Reference in New Issue
Block a user