From 7329e20fa854454f1cbe1b2e0b6ef0e012e87456 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 3 Nov 2016 16:19:46 +0100 Subject: [PATCH] DATAREST-919 - Merging of nested maps for PUT/PATCH requests now handles nested arrays and simple types. --- .../rest/webmvc/json/DomainObjectReader.java | 8 ++- .../json/DomainObjectReaderUnitTests.java | 61 ++++++++++++++++++- 2 files changed, 67 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 5879dfa4a..507f202f5 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 @@ -282,8 +282,14 @@ public class DomainObjectReader { if (child instanceof ObjectNode && sourceValue != null) { doMerge((ObjectNode) child, sourceValue, mapper); - fields.remove(); + } else if (child instanceof ArrayNode && sourceValue != null) { + handleArrayNode((ArrayNode) child, asCollection(sourceValue), mapper); + } else { + source.put(entry.getKey(), + mapper.treeToValue(child, sourceValue == null ? Object.class : sourceValue.getClass())); } + + fields.remove(); } } 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 9adbd23c4..85fcc61cb 100644 --- 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 @@ -21,6 +21,7 @@ import static org.mockito.Mockito.*; import java.io.ByteArrayInputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.Date; @@ -137,6 +138,7 @@ public class DomainObjectReaderUnitTests { * @see DATAREST-701 */ @Test + @SuppressWarnings("unchecked") public void mergesNestedMapWithoutTypeInformation() throws Exception { ObjectMapper mapper = new ObjectMapper(); @@ -146,7 +148,13 @@ public class DomainObjectReaderUnitTests { target.map = new HashMap(); target.map.put("b", new HashMap()); - reader.readPut((ObjectNode) node, target, mapper); + TypeWithGenericMap result = reader.readPut((ObjectNode) node, target, mapper); + + assertThat(result.map.get("a"), is((Object) "1")); + + Object object = result.map.get("b"); + assertThat(object, is(instanceOf(Map.class))); + assertThat(((Map) object).get("c"), is((Object) "2")); } /** @@ -200,6 +208,9 @@ public class DomainObjectReaderUnitTests { assertThat(reader.readPut(node, sample, mapper).createdDate, is(reference)); } + /** + * @see DATAREST-931 + */ @Test public void readsPatchForEntityNestedInCollection() throws Exception { @@ -217,6 +228,54 @@ public class DomainObjectReaderUnitTests { assertThat(result.phones.get(0).creationDate, is(notNullValue())); } + /** + * @see DATAREST-919 + */ + @Test + @SuppressWarnings("unchecked") + public void readsComplexNestedMapsAndArrays() throws Exception { + + Map childMap = new HashMap(); + childMap.put("child1", "ok"); + + HashMap nestedMap = new HashMap(); + nestedMap.put("c1", "v1"); + + TypeWithGenericMap map = new TypeWithGenericMap(); + map.map = new HashMap(); + map.map.put("sub1", "ok"); + map.map.put("sub2", new ArrayList(Arrays.asList("ok1", "ok2"))); + map.map.put("sub3", new ArrayList(Arrays.asList(childMap))); + map.map.put("sub4", nestedMap); + + ObjectMapper mapper = new ObjectMapper(); + ObjectNode payload = (ObjectNode) mapper.readTree("{ \"map\" : { \"sub1\" : \"ok\"," + + " \"sub2\" : [ \"ok1\", \"ok2\" ], \"sub3\" : [ { \"childOk1\" : \"ok\" }], \"sub4\" : {" + + " \"c1\" : \"v1\", \"c2\" : \"new\" } } }"); + + TypeWithGenericMap result = reader.readPut(payload, map, mapper); + + assertThat(result.map.get("sub1"), is((Object) "ok")); + + List sub2 = as(result.map.get("sub2"), List.class); + assertThat(sub2.get(0), is("ok1")); + assertThat(sub2.get(1), is("ok2")); + + List> sub3 = as(result.map.get("sub3"), List.class); + assertThat(sub3.get(0).get("childOk1"), is("ok")); + + Map sub4 = as(result.map.get("sub4"), Map.class); + assertThat(sub4.get("c1"), is("v1")); + assertThat(sub4.get("c2"), is("new")); + } + + @SuppressWarnings("unchecked") + private static T as(Object source, Class type) { + + assertThat(source, is(instanceOf(type))); + return (T) source; + } + @JsonAutoDetect(fieldVisibility = Visibility.ANY) static class SampleUser {