Skip to content

Commit f2c9ec3

Browse files
committed
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
1 parent 2885f76 commit f2c9ec3

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/DomainObjectReader.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.springframework.data.rest.webmvc.mapping.Associations;
4141
import org.springframework.data.rest.webmvc.util.InputStreamHttpInputMessage;
4242
import org.springframework.data.util.ClassTypeInformation;
43+
import org.springframework.data.util.Optionals;
4344
import org.springframework.data.util.TypeInformation;
4445
import org.springframework.http.converter.HttpMessageNotReadableException;
4546
import org.springframework.lang.Nullable;
@@ -61,6 +62,7 @@
6162
* @author Craig Andrews
6263
* @author Mathias Düsterhöft
6364
* @author Thomas Mrozinski
65+
* @author Lars Vierbergen
6466
* @since 2.2
6567
*/
6668
public class DomainObjectReader {
@@ -678,7 +680,7 @@ public void doWithPersistentProperty(PersistentProperty<?> property) {
678680
} else if (property.isCollectionLike()) {
679681
result = mergeCollections(property, sourceValue, targetValue, mapper);
680682
} else if (property.isEntity()) {
681-
result = mergeForPut(sourceValue, targetValue, mapper);
683+
result = Optionals.mapIfAllPresent(sourceValue, targetValue, (l, r) -> mergeForPut(l, r, mapper));
682684
} else {
683685
result = sourceValue;
684686
}

spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/DomainObjectReaderUnitTests.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,33 @@ void writesPolymorphicArrayWithSwitchedItemForPut() throws Exception {
618618
});
619619
}
620620

621+
@Test // #2174
622+
void nestedEntitiesWithReadonlyFieldAreKeptForPut() throws Exception {
623+
624+
Inner inner = new Inner();
625+
inner.name = "inner name";
626+
inner.prop = "something";
627+
inner.readOnly = "readonly value";
628+
inner.hidden = "hidden value";
629+
630+
Outer outer = new Outer();
631+
outer.prop = "else";
632+
outer.name = "outer name";
633+
outer.inner = inner;
634+
635+
JsonNode node = new ObjectMapper().readTree("{ \"inner\" : { \"name\" : \"new inner name\" } }");
636+
637+
Outer result = reader.readPut((ObjectNode) node, outer, new ObjectMapper());
638+
639+
assertThat(result).isSameAs(outer);
640+
assertThat(result.prop).isNull();
641+
assertThat(result.inner.prop).isNull();
642+
assertThat(result.inner.name).isEqualTo("new inner name");
643+
assertThat(result.inner.readOnly).isEqualTo("readonly value");
644+
assertThat(result.inner.hidden).isEqualTo("hidden value");
645+
assertThat(result.inner).isSameAs(inner);
646+
}
647+
621648
@SuppressWarnings("unchecked")
622649
private static <T> T as(Object source, Class<T> type) {
623650

@@ -715,6 +742,8 @@ static class Inner {
715742

716743
String name;
717744
String prop;
745+
@JsonProperty(access = READ_ONLY) String readOnly;
746+
@JsonIgnore String hidden;
718747
}
719748

720749
@JsonAutoDetect(fieldVisibility = Visibility.ANY)

0 commit comments

Comments
 (0)