Skip to content

Commit 2710b98

Browse files
committed
DATAREST-885, DATAREST-885 - Cleanups in JSON Patch code.
1 parent 2493d3c commit 2710b98

24 files changed

+256
-260
lines changed

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

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014 the original author or authors.
2+
* Copyright 2014-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,26 +16,30 @@
1616
package org.springframework.data.rest.webmvc.json.patch;
1717

1818
/**
19-
* Operation to add a new value to the given "path".
20-
* Will throw a {@link PatchException} if the path is invalid or if the given value
21-
* is not assignable to the given path.
19+
* Operation to add a new value to the given "path". Will throw a {@link PatchException} if the path is invalid or if
20+
* the given value is not assignable to the given path.
2221
*
2322
* @author Craig Walls
23+
* @author Oliver Gierke
2424
*/
25-
public class AddOperation extends PatchOperation {
25+
class AddOperation extends PatchOperation {
2626

2727
/**
2828
* Constructs the add operation
29+
*
2930
* @param path The path where the value will be added. (e.g., '/foo/bar/4')
3031
* @param value The value to add.
3132
*/
3233
public AddOperation(String path, Object value) {
3334
super("add", path, value);
3435
}
35-
36+
37+
/*
38+
* (non-Javadoc)
39+
* @see org.springframework.data.rest.webmvc.json.patch.PatchOperation#perform(java.lang.Object, java.lang.Class)
40+
*/
3641
@Override
3742
<T> void perform(Object targetObject, Class<T> type) {
3843
addValue(targetObject, evaluateValueFromTarget(targetObject, type));
3944
}
40-
4145
}

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014 the original author or authors.
2+
* Copyright 2014-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -37,8 +37,9 @@
3737
* </p>
3838
*
3939
* @author Craig Walls
40+
* @author Oliver Gierke
4041
*/
41-
public class CopyOperation extends FromOperation {
42+
class CopyOperation extends FromOperation {
4243

4344
/**
4445
* Constructs the copy operation
@@ -50,9 +51,12 @@ public CopyOperation(String path, String from) {
5051
super("copy", path, from);
5152
}
5253

54+
/*
55+
* (non-Javadoc)
56+
* @see org.springframework.data.rest.webmvc.json.patch.PatchOperation#perform(java.lang.Object, java.lang.Class)
57+
*/
5358
@Override
5459
<T> void perform(Object target, Class<T> type) {
55-
addValue(target, pathToExpression(from).getValue(target));
60+
addValue(target, pathToExpression(getFrom()).getValue(target));
5661
}
57-
5862
}

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

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014 the original author or authors.
2+
* Copyright 2014-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,16 +16,19 @@
1616
package org.springframework.data.rest.webmvc.json.patch;
1717

1818
/**
19-
* Abstract base class for operations requiring a source property, such as "copy" and "move".
20-
* (e.g., copy <i>from</i> here to there.
19+
* Abstract base class for operations requiring a source property, such as "copy" and "move". (e.g., copy <i>from</i>
20+
* here to there.
21+
*
2122
* @author Craig Walls
23+
* @author Oliver Gierke
2224
*/
23-
public abstract class FromOperation extends PatchOperation {
25+
abstract class FromOperation extends PatchOperation {
26+
27+
private final String from;
2428

25-
protected String from;
26-
2729
/**
2830
* Constructs the operation
31+
*
2932
* @param op The name of the operation to perform. (e.g., 'copy')
3033
* @param path The operation's target path. (e.g., '/foo/bar/4')
3134
* @param from The operation's source path. (e.g., '/foo/bar/5')
@@ -34,9 +37,8 @@ public FromOperation(String op, String path, String from) {
3437
super(op, path);
3538
this.from = from;
3639
}
37-
40+
3841
public String getFrom() {
3942
return from;
4043
}
41-
4244
}

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

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
*/
1616
package org.springframework.data.rest.webmvc.json.patch;
1717

18+
import lombok.NonNull;
19+
import lombok.RequiredArgsConstructor;
20+
1821
import com.fasterxml.jackson.databind.JsonNode;
1922
import com.fasterxml.jackson.databind.ObjectMapper;
2023

@@ -23,23 +26,23 @@
2326
*
2427
* @author Craig Walls
2528
*/
29+
@RequiredArgsConstructor
2630
class JsonLateObjectEvaluator implements LateObjectEvaluator {
2731

28-
private static final ObjectMapper MAPPER = new ObjectMapper();
29-
30-
private JsonNode valueNode;
31-
32-
public JsonLateObjectEvaluator(JsonNode valueNode) {
33-
this.valueNode = valueNode;
34-
}
32+
private final @NonNull ObjectMapper mapper;
33+
private final @NonNull JsonNode valueNode;
3534

35+
/*
36+
* (non-Javadoc)
37+
* @see org.springframework.data.rest.webmvc.json.patch.LateObjectEvaluator#evaluate(java.lang.Class)
38+
*/
3639
@Override
3740
public <T> Object evaluate(Class<T> type) {
41+
3842
try {
39-
return MAPPER.readValue(valueNode.traverse(), type);
43+
return mapper.readValue(valueNode.traverse(), type);
4044
} catch (Exception e) {
4145
return null;
4246
}
4347
}
44-
4548
}

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

Lines changed: 17 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@
1515
*/
1616
package org.springframework.data.rest.webmvc.json.patch;
1717

18+
import lombok.NonNull;
19+
import lombok.RequiredArgsConstructor;
20+
1821
import java.util.ArrayList;
1922
import java.util.Iterator;
2023
import java.util.List;
2124

22-
import org.springframework.util.Assert;
23-
24-
import com.fasterxml.jackson.core.JsonPointer;
2525
import com.fasterxml.jackson.databind.JsonNode;
2626
import com.fasterxml.jackson.databind.ObjectMapper;
2727
import com.fasterxml.jackson.databind.node.ArrayNode;
@@ -35,21 +35,10 @@
3535
* @author Oliver Gierke
3636
* @author Mathias Düsterhöft
3737
*/
38+
@RequiredArgsConstructor
3839
public class JsonPatchPatchConverter implements PatchConverter<JsonNode> {
3940

40-
private final ObjectMapper mapper;
41-
42-
/**
43-
* Creates a new {@link JsonPatchPatchConverter} for the given {@link ObjectMapper}.
44-
*
45-
* @param mapper must not be {@literal null}.
46-
*/
47-
public JsonPatchPatchConverter(ObjectMapper mapper) {
48-
49-
Assert.notNull(mapper, "ObjectMapper must not be null!");
50-
51-
this.mapper = mapper;
52-
}
41+
private final @NonNull ObjectMapper mapper;
5342

5443
/**
5544
* Constructs a {@link Patch} object given a JsonNode.
@@ -58,13 +47,16 @@ public JsonPatchPatchConverter(ObjectMapper mapper) {
5847
* @return a {@link Patch}
5948
*/
6049
public Patch convert(JsonNode jsonNode) {
50+
6151
if (!(jsonNode instanceof ArrayNode)) {
6252
throw new IllegalArgumentException("JsonNode must be an instance of ArrayNode");
6353
}
6454

6555
ArrayNode opNodes = (ArrayNode) jsonNode;
6656
List<PatchOperation> ops = new ArrayList<PatchOperation>(opNodes.size());
57+
6758
for (Iterator<JsonNode> elements = opNodes.elements(); elements.hasNext();) {
59+
6860
JsonNode opNode = elements.next();
6961

7062
String opType = opNode.get("op").textValue();
@@ -105,25 +97,33 @@ public JsonNode convert(Patch patch) {
10597
List<PatchOperation> operations = patch.getOperations();
10698
JsonNodeFactory nodeFactory = JsonNodeFactory.instance;
10799
ArrayNode patchNode = nodeFactory.arrayNode();
100+
108101
for (PatchOperation operation : operations) {
102+
109103
ObjectNode opNode = nodeFactory.objectNode();
110104
opNode.set("op", nodeFactory.textNode(operation.getOp()));
111105
opNode.set("path", nodeFactory.textNode(operation.getPath()));
106+
112107
if (operation instanceof FromOperation) {
108+
113109
FromOperation fromOp = (FromOperation) operation;
114110
opNode.set("from", nodeFactory.textNode(fromOp.getFrom()));
115111
}
112+
116113
Object value = operation.getValue();
114+
117115
if (value != null) {
118116
opNode.set("value", mapper.valueToTree(value));
119117
}
118+
120119
patchNode.add(opNode);
121120
}
122121

123122
return patchNode;
124123
}
125124

126125
private Object valueFromJsonNode(String path, JsonNode valueNode) {
126+
127127
if (valueNode == null || valueNode.isNull()) {
128128
return null;
129129
} else if (valueNode.isTextual()) {
@@ -137,36 +137,11 @@ private Object valueFromJsonNode(String path, JsonNode valueNode) {
137137
} else if (valueNode.isLong()) {
138138
return valueNode.asLong();
139139
} else if (valueNode.isObject()) {
140-
return new JsonLateObjectEvaluator(valueNode);
140+
return new JsonLateObjectEvaluator(mapper, valueNode);
141141
} else if (valueNode.isArray()) {
142142
// TODO: Convert valueNode to array
143143
}
144144

145145
return null;
146146
}
147-
148-
/**
149-
* Returns whether the trailing element of the given {@link JsonPointer} is a pointer into an array or collection.
150-
*
151-
* @param pointer must not be {@literal null}.
152-
* @return
153-
*/
154-
private static boolean isCollectionElementReference(String pointer) {
155-
156-
String[] segments = pointer.split("/");
157-
158-
if (segments.length == 0) {
159-
return false;
160-
}
161-
162-
String trailing = segments[segments.length - 1];
163-
164-
try {
165-
Integer.parseInt(trailing);
166-
return true;
167-
} catch (NumberFormatException o_O) {
168-
return false;
169-
}
170-
}
171-
172147
}

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

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014 the original author or authors.
2+
* Copyright 2014-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,24 +19,20 @@
1919
* <p>
2020
* Strategy interface for resolving values from an operation definition.
2121
* </p>
22-
*
2322
* <p>
24-
* {@link Patch} implementation generically defines a patch without being tied to any particular
25-
* patch specification. But it's important to know the patch format when resolving the value of
26-
* an operation, as the value format will likely be tied to the patch specification. For example,
27-
* the <code>value</code> attribute of a JSON Patch operation will contain a JSON object. A different
28-
* patch specification may define values in some non-JSON format.
23+
* {@link Patch} implementation generically defines a patch without being tied to any particular patch specification.
24+
* But it's important to know the patch format when resolving the value of an operation, as the value format will likely
25+
* be tied to the patch specification. For example, the <code>value</code> attribute of a JSON Patch operation will
26+
* contain a JSON object. A different patch specification may define values in some non-JSON format.
2927
* </p>
30-
*
3128
* <p>
32-
* This interface allows for pluggable evaluation of values, allowing {@link Patch} to remain
33-
* independent of any specific patch representation.
29+
* This interface allows for pluggable evaluation of values, allowing {@link Patch} to remain independent of any
30+
* specific patch representation.
3431
* </p>
3532
*
3633
* @author Craig Walls
3734
*/
3835
public interface LateObjectEvaluator {
3936

4037
<T> Object evaluate(Class<T> type);
41-
4238
}
Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014 the original author or authors.
2+
* Copyright 2014-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,34 +17,37 @@
1717

1818
/**
1919
* <p>
20-
* Operation that moves a value from the given "from" path to the given "path".
21-
* Will throw a {@link PatchException} if either path is invalid or if the from path is non-nullable.
20+
* Operation that moves a value from the given "from" path to the given "path". Will throw a {@link PatchException} if
21+
* either path is invalid or if the from path is non-nullable.
2222
* </p>
23-
*
2423
* <p>
25-
* NOTE: When dealing with lists, the move operation may effectively be a no-op.
26-
* That's because the order of a list is probably dictated by a database query that produced the list.
27-
* Moving things around in the list will have no bearing on the values of each item in the list.
28-
* When the same list resource is retrieved again later, the order will again be decided by the query,
29-
* effectively undoing any previous move operation.
24+
* NOTE: When dealing with lists, the move operation may effectively be a no-op. That's because the order of a list is
25+
* probably dictated by a database query that produced the list. Moving things around in the list will have no bearing
26+
* on the values of each item in the list. When the same list resource is retrieved again later, the order will again be
27+
* decided by the query, effectively undoing any previous move operation.
3028
* </p>
3129
*
3230
* @author Craig Walls
31+
* @author Oliver Gierke
3332
*/
34-
public class MoveOperation extends FromOperation {
33+
class MoveOperation extends FromOperation {
3534

3635
/**
3736
* Constructs the move operation.
37+
*
3838
* @param path The path to move the source value to. (e.g., '/foo/bar/4')
3939
* @param from The source path from which a value will be moved. (e.g., '/foo/bar/5')
4040
*/
4141
public MoveOperation(String path, String from) {
4242
super("move", path, from);
4343
}
44-
44+
45+
/*
46+
* (non-Javadoc)
47+
* @see org.springframework.data.rest.webmvc.json.patch.PatchOperation#perform(java.lang.Object, java.lang.Class)
48+
*/
4549
@Override
4650
<T> void perform(Object target, Class<T> type) {
47-
addValue(target, popValueAtPath(target, from));
51+
addValue(target, popValueAtPath(target, getFrom()));
4852
}
49-
5053
}

0 commit comments

Comments
 (0)