Skip to content

Commit

Permalink
Properly deep-merge nested documents on PUT.
Browse files Browse the repository at this point in the history
This is needed to consider read-only properties within those objects as those would otherwise get overridden.

Fixes: #2174
  • Loading branch information
odrotbohm committed Feb 21, 2023
1 parent 2885f76 commit f2c9ec3
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
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;
Expand All @@ -61,6 +62,7 @@
* @author Craig Andrews
* @author Mathias Düsterhöft
* @author Thomas Mrozinski
* @author Lars Vierbergen
* @since 2.2
*/
public class DomainObjectReader {
Expand Down Expand Up @@ -678,7 +680,7 @@ public void doWithPersistentProperty(PersistentProperty<?> property) {
} 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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,33 @@ void writesPolymorphicArrayWithSwitchedItemForPut() throws Exception {
});
}

@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) {

Expand Down Expand Up @@ -715,6 +742,8 @@ static class Inner {

String name;
String prop;
@JsonProperty(access = READ_ONLY) String readOnly;
@JsonIgnore String hidden;
}

@JsonAutoDetect(fieldVisibility = Visibility.ANY)
Expand Down

0 comments on commit f2c9ec3

Please sign in to comment.