DATAREST-1338 - JsonPatch handling is now able to traverse maps.
We're now able to correctly identify Map keys within JsonPatch paths so that e.g. people/Dave/name properly translates into a people['Dave'].name SpEL expression. Streamlined the design of SpelPath to avoid duplicate parsing and properly express the difference between typed and untyped paths in the type hierarchy. Slightly refactored the type hierarchy so that only methods that make sense in either untyped or typed state appear on the instance returned (getLeafType(Class) was exposed on TypedSpelPath before, which was confusing).
This commit is contained in:
@@ -15,13 +15,17 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.json.patch;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
public class ReplaceOperationTests {
|
||||
@@ -82,4 +86,30 @@ public class ReplaceOperationTests {
|
||||
assertNotNull(todo.getType().getValue());
|
||||
assertTrue(todo.getType().getValue().equals("new"));
|
||||
}
|
||||
|
||||
@Test // DATAREST-1338
|
||||
public void replacesMapValueCorrectly() throws Exception {
|
||||
|
||||
Book book = new Book();
|
||||
book.characters = new HashMap<>();
|
||||
book.characters.put("protagonist", "Pinco");
|
||||
|
||||
ReplaceOperation.valueAt("/characters/protagonist") //
|
||||
.with(prepareValue("\"Pallo\"")) //
|
||||
.perform(book, Book.class);
|
||||
|
||||
assertThat(book.characters.get("protagonist")).isEqualTo("Pallo");
|
||||
}
|
||||
|
||||
private static Object prepareValue(String json) throws Exception {
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode node = mapper.readTree(json);
|
||||
return new JsonLateObjectEvaluator(mapper, node);
|
||||
}
|
||||
|
||||
// DATAREST-1338
|
||||
class Book {
|
||||
public Map<String, String> characters;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,11 @@ import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.rest.webmvc.json.patch.SpelPath.TypedSpelPath;
|
||||
import org.springframework.data.rest.webmvc.json.patch.SpelPath.UntypedSpelPath;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link SpelPath}.
|
||||
@@ -34,34 +36,34 @@ public class SpelPathUnitTests {
|
||||
@Test
|
||||
public void listIndex() {
|
||||
|
||||
SpelPath expr = SpelPath.of("/1/description");
|
||||
UntypedSpelPath expr = SpelPath.untyped("/1/description");
|
||||
|
||||
List<Todo> todos = new ArrayList<Todo>();
|
||||
todos.add(new Todo(1L, "A", false));
|
||||
todos.add(new Todo(2L, "B", false));
|
||||
todos.add(new Todo(3L, "C", false));
|
||||
|
||||
assertEquals("B", (String) expr.bindTo(Todo.class).getValue(todos));
|
||||
assertEquals("B", expr.bindTo(Todo.class).getValue(todos));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessesLastCollectionElementWithDash() {
|
||||
|
||||
SpelPath expr = SpelPath.of("/-/description");
|
||||
UntypedSpelPath expr = SpelPath.untyped("/-/description");
|
||||
|
||||
List<Todo> todos = new ArrayList<Todo>();
|
||||
todos.add(new Todo(1L, "A", false));
|
||||
todos.add(new Todo(2L, "B", false));
|
||||
todos.add(new Todo(3L, "C", false));
|
||||
|
||||
assertEquals("C", (String) expr.bindTo(Todo.class).getValue(todos));
|
||||
assertEquals("C", expr.bindTo(Todo.class).getValue(todos));
|
||||
}
|
||||
|
||||
@Test // DATAREST-1152
|
||||
public void cachesSpelPath() {
|
||||
|
||||
SpelPath left = SpelPath.of("/description");
|
||||
SpelPath right = SpelPath.of("/description");
|
||||
UntypedSpelPath left = SpelPath.untyped("/description");
|
||||
UntypedSpelPath right = SpelPath.untyped("/description");
|
||||
|
||||
assertSame(left, right);
|
||||
}
|
||||
@@ -69,7 +71,7 @@ public class SpelPathUnitTests {
|
||||
@Test // DATAREST-1152
|
||||
public void cachesTypedSpelPath() {
|
||||
|
||||
SpelPath source = SpelPath.of("/description");
|
||||
UntypedSpelPath source = SpelPath.untyped("/description");
|
||||
TypedSpelPath left = source.bindTo(Todo.class);
|
||||
TypedSpelPath right = source.bindTo(Todo.class);
|
||||
|
||||
@@ -78,6 +80,35 @@ public class SpelPathUnitTests {
|
||||
|
||||
@Test // DATAREST-1274
|
||||
public void supportsMultiDigitCollectionIndex() {
|
||||
assertThat(SpelPath.of("/11/description").getLeafType(Todo.class)).isEqualTo(String.class);
|
||||
assertThat(SpelPath.untyped("/11/description").bindTo(Todo.class).getLeafType()).isEqualTo(String.class);
|
||||
}
|
||||
|
||||
@Test // DATAREST-1338
|
||||
public void handlesStringMapKeysInPathExpressions() {
|
||||
|
||||
TypedSpelPath path = SpelPath.untyped("people/Dave/name").bindTo(MapWrapper.class);
|
||||
|
||||
assertThat(path.getExpressionString()).isEqualTo("people['Dave'].name");
|
||||
assertThat(path.getLeafType()).isEqualTo(String.class);
|
||||
}
|
||||
|
||||
@Test // DATAREST-1338
|
||||
public void handlesIntegerMapKeysInPathExpressions() {
|
||||
|
||||
TypedSpelPath path = SpelPath.untyped("peopleByInt/0/name").bindTo(MapWrapper.class);
|
||||
|
||||
assertThat(path.getExpressionString()).isEqualTo("peopleByInt[0].name");
|
||||
assertThat(path.getLeafType()).isEqualTo(String.class);
|
||||
}
|
||||
|
||||
// DATAREST-1338
|
||||
|
||||
static class Person {
|
||||
String name;
|
||||
}
|
||||
|
||||
static class MapWrapper {
|
||||
Map<String, Person> people;
|
||||
Map<Integer, Person> peopleByInt;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user