Skip to content

Commit c729ada

Browse files
committed
DATAREST-919 - Merging of nested maps for PUT/PATCH requests now handles nested arrays and simple types.
1 parent 4391e24 commit c729ada

File tree

2 files changed

+67
-2
lines changed

2 files changed

+67
-2
lines changed

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,14 @@ private void doMergeNestedMap(Map<String, Object> source, ObjectNode node, Objec
298298

299299
if (child instanceof ObjectNode && sourceValue != null) {
300300
doMerge((ObjectNode) child, sourceValue, mapper);
301-
fields.remove();
301+
} else if (child instanceof ArrayNode && sourceValue != null) {
302+
handleArrayNode((ArrayNode) child, asCollection(sourceValue), mapper);
303+
} else {
304+
source.put(entry.getKey(),
305+
mapper.treeToValue(child, sourceValue == null ? Object.class : sourceValue.getClass()));
302306
}
307+
308+
fields.remove();
303309
}
304310
}
305311

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

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import java.io.ByteArrayInputStream;
2222
import java.util.ArrayList;
23+
import java.util.Arrays;
2324
import java.util.Calendar;
2425
import java.util.Collections;
2526
import java.util.Date;
@@ -134,6 +135,7 @@ public void mergesMapCorrectly() throws Exception {
134135
* @see DATAREST-701
135136
*/
136137
@Test
138+
@SuppressWarnings("unchecked")
137139
public void mergesNestedMapWithoutTypeInformation() throws Exception {
138140

139141
ObjectMapper mapper = new ObjectMapper();
@@ -143,7 +145,13 @@ public void mergesNestedMapWithoutTypeInformation() throws Exception {
143145
target.map = new HashMap<String, Object>();
144146
target.map.put("b", new HashMap<String, Object>());
145147

146-
reader.readPut((ObjectNode) node, target, mapper);
148+
TypeWithGenericMap result = reader.readPut((ObjectNode) node, target, mapper);
149+
150+
assertThat(result.map.get("a"), is((Object) "1"));
151+
152+
Object object = result.map.get("b");
153+
assertThat(object, is(instanceOf(Map.class)));
154+
assertThat(((Map<Object, Object>) object).get("c"), is((Object) "2"));
147155
}
148156

149157
/**
@@ -197,6 +205,9 @@ public void doesNotApplyInputToReadOnlyFields() throws Exception {
197205
assertThat(reader.readPut(node, sample, mapper).createdDate, is(reference));
198206
}
199207

208+
/**
209+
* @see DATAREST-931
210+
*/
200211
@Test
201212
public void readsPatchForEntityNestedInCollection() throws Exception {
202213

@@ -214,6 +225,54 @@ public void readsPatchForEntityNestedInCollection() throws Exception {
214225
assertThat(result.phones.get(0).creationDate, is(notNullValue()));
215226
}
216227

228+
/**
229+
* @see DATAREST-919
230+
*/
231+
@Test
232+
@SuppressWarnings("unchecked")
233+
public void readsComplexNestedMapsAndArrays() throws Exception {
234+
235+
Map<String, Object> childMap = new HashMap<String, Object>();
236+
childMap.put("child1", "ok");
237+
238+
HashMap<String, Object> nestedMap = new HashMap<String, Object>();
239+
nestedMap.put("c1", "v1");
240+
241+
TypeWithGenericMap map = new TypeWithGenericMap();
242+
map.map = new HashMap<String, Object>();
243+
map.map.put("sub1", "ok");
244+
map.map.put("sub2", new ArrayList<String>(Arrays.asList("ok1", "ok2")));
245+
map.map.put("sub3", new ArrayList<Object>(Arrays.asList(childMap)));
246+
map.map.put("sub4", nestedMap);
247+
248+
ObjectMapper mapper = new ObjectMapper();
249+
ObjectNode payload = (ObjectNode) mapper.readTree("{ \"map\" : { \"sub1\" : \"ok\","
250+
+ " \"sub2\" : [ \"ok1\", \"ok2\" ], \"sub3\" : [ { \"childOk1\" : \"ok\" }], \"sub4\" : {"
251+
+ " \"c1\" : \"v1\", \"c2\" : \"new\" } } }");
252+
253+
TypeWithGenericMap result = reader.readPut(payload, map, mapper);
254+
255+
assertThat(result.map.get("sub1"), is((Object) "ok"));
256+
257+
List<String> sub2 = as(result.map.get("sub2"), List.class);
258+
assertThat(sub2.get(0), is("ok1"));
259+
assertThat(sub2.get(1), is("ok2"));
260+
261+
List<Map<String, String>> sub3 = as(result.map.get("sub3"), List.class);
262+
assertThat(sub3.get(0).get("childOk1"), is("ok"));
263+
264+
Map<Object, String> sub4 = as(result.map.get("sub4"), Map.class);
265+
assertThat(sub4.get("c1"), is("v1"));
266+
assertThat(sub4.get("c2"), is("new"));
267+
}
268+
269+
@SuppressWarnings("unchecked")
270+
private static <T> T as(Object source, Class<T> type) {
271+
272+
assertThat(source, is(instanceOf(type)));
273+
return (T) source;
274+
}
275+
217276
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
218277
static class SampleUser {
219278

0 commit comments

Comments
 (0)