Skip to content

Commit fffdd1e

Browse files
candrewssbrannen
authored andcommitted
Introduce additional JsonPath matchers in Spring MVC Test
This commit introduces the following methods in JsonPathResultMatchers in the Spring MVC Test framework. - isString() - isBoolean() - isNumber() - isMap() In addition, this commit overhauls the Javadoc in JsonPathResultMatchers and JsonPathExpectationsHelper. Issue: SPR-13320
1 parent 48b965a commit fffdd1e

File tree

5 files changed

+293
-104
lines changed

5 files changed

+293
-104
lines changed

spring-test/src/main/java/org/springframework/test/util/JsonPathExpectationsHelper.java

Lines changed: 119 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,21 @@
2020
import java.lang.reflect.Method;
2121
import java.text.ParseException;
2222
import java.util.List;
23+
import java.util.Map;
2324

24-
import com.jayway.jsonpath.InvalidPathException;
25-
import com.jayway.jsonpath.JsonPath;
2625
import org.hamcrest.Matcher;
2726

2827
import org.springframework.util.Assert;
2928
import org.springframework.util.ReflectionUtils;
3029

31-
import static org.hamcrest.MatcherAssert.*;
32-
import static org.springframework.test.util.AssertionErrors.*;
30+
import com.jayway.jsonpath.InvalidPathException;
31+
import com.jayway.jsonpath.JsonPath;
32+
33+
import static org.hamcrest.MatcherAssert.assertThat;
34+
import static org.hamcrest.core.IsInstanceOf.instanceOf;
35+
import static org.springframework.test.util.AssertionErrors.assertEquals;
36+
import static org.springframework.test.util.AssertionErrors.assertTrue;
37+
import static org.springframework.test.util.AssertionErrors.fail;
3338

3439
/**
3540
* A helper class for applying assertions via JSON path expressions.
@@ -39,6 +44,8 @@
3944
*
4045
* @author Rossen Stoyanchev
4146
* @author Juergen Hoeller
47+
* @author Craig Andrews
48+
* @author Sam Brannen
4249
* @since 3.2
4350
*/
4451
public class JsonPathExpectationsHelper {
@@ -69,92 +76,130 @@ public class JsonPathExpectationsHelper {
6976

7077

7178
/**
72-
* Construct a new JsonPathExpectationsHelper.
73-
* @param expression the JsonPath expression
74-
* @param args arguments to parameterize the JSON path expression with
79+
* Construct a new {@code JsonPathExpectationsHelper}.
80+
* @param expression the {@link JsonPath} expression; never {@code null} or empty
81+
* @param args arguments to parameterize the {@code JsonPath} expression, with
7582
* formatting specifiers defined in {@link String#format(String, Object...)}
7683
*/
7784
public JsonPathExpectationsHelper(String expression, Object... args) {
85+
Assert.hasText(expression, "expression must not be null or empty");
7886
this.expression = String.format(expression, args);
7987
this.jsonPath = (JsonPath) ReflectionUtils.invokeMethod(
8088
compileMethod, null, this.expression, emptyFilters);
8189
}
8290

8391

8492
/**
85-
* Evaluate the JSON path and assert the resulting value with the given {@code Matcher}.
86-
* @param content the response content
87-
* @param matcher the matcher to assert on the resulting json path
93+
* Evaluate the JSON path expression against the supplied {@code content}
94+
* and assert the resulting value with the given {@code Matcher}.
95+
* @param content the JSON response content
96+
* @param matcher the matcher with which to assert the result
8897
*/
8998
@SuppressWarnings("unchecked")
9099
public <T> void assertValue(String content, Matcher<T> matcher) throws ParseException {
91100
T value = (T) evaluateJsonPath(content);
92-
assertThat("JSON path " + this.expression, value, matcher);
93-
}
94-
95-
private Object evaluateJsonPath(String content) throws ParseException {
96-
String message = "No value for JSON path: " + this.expression + ", exception: ";
97-
try {
98-
return this.jsonPath.read(content);
99-
}
100-
catch (InvalidPathException ex) {
101-
throw new AssertionError(message + ex.getMessage());
102-
}
103-
catch (ArrayIndexOutOfBoundsException ex) {
104-
throw new AssertionError(message + ex.getMessage());
105-
}
106-
catch (IndexOutOfBoundsException ex) {
107-
throw new AssertionError(message + ex.getMessage());
108-
}
101+
assertThat("JSON path \"" + this.expression + "\"", value, matcher);
109102
}
110103

111104
/**
112-
* Apply the JSON path and assert the resulting value.
105+
* Evaluate the JSON path expression against the supplied {@code content}
106+
* and assert that the result is equal to the expected value.
107+
* @param content the JSON response content
108+
* @param expectedValue the expected value
113109
*/
114-
public void assertValue(String responseContent, Object expectedValue) throws ParseException {
115-
Object actualValue = evaluateJsonPath(responseContent);
110+
public void assertValue(String content, Object expectedValue) throws ParseException {
111+
Object actualValue = evaluateJsonPath(content);
116112
if ((actualValue instanceof List) && !(expectedValue instanceof List)) {
117113
@SuppressWarnings("rawtypes")
118114
List actualValueList = (List) actualValue;
119115
if (actualValueList.isEmpty()) {
120116
fail("No matching value for JSON path \"" + this.expression + "\"");
121117
}
122118
if (actualValueList.size() != 1) {
123-
fail("Got a list of values " + actualValue + " instead of the value " + expectedValue);
119+
fail("Got a list of values " + actualValue + " instead of the expected single value " + expectedValue);
124120
}
125121
actualValue = actualValueList.get(0);
126122
}
127123
else if (actualValue != null && expectedValue != null) {
128-
assertEquals("For JSON path " + this.expression + " type of value",
129-
expectedValue.getClass(), actualValue.getClass());
124+
assertEquals("For JSON path \"" + this.expression + "\", type of value",
125+
expectedValue.getClass().getName(), actualValue.getClass().getName());
130126
}
131-
assertEquals("JSON path " + this.expression, expectedValue, actualValue);
127+
assertEquals("JSON path \"" + this.expression + "\"", expectedValue, actualValue);
128+
}
129+
130+
/**
131+
* Evaluate the JSON path expression against the supplied {@code content}
132+
* and assert that the resulting value is a {@link String}.
133+
* @param content the JSON response content
134+
* @since 4.2.1
135+
*/
136+
public void assertValueIsString(String content) throws ParseException {
137+
Object value = assertExistsAndReturn(content);
138+
String reason = "Expected string at JSON path " + this.expression + " but found " + value;
139+
assertThat(reason, value, instanceOf(String.class));
140+
}
141+
142+
/**
143+
* Evaluate the JSON path expression against the supplied {@code content}
144+
* and assert that the resulting value is a {@link Boolean}.
145+
* @param content the JSON response content
146+
* @since 4.2.1
147+
*/
148+
public void assertValueIsBoolean(String content) throws ParseException {
149+
Object value = assertExistsAndReturn(content);
150+
String reason = "Expected boolean at JSON path " + this.expression + " but found " + value;
151+
assertThat(reason, value, instanceOf(Boolean.class));
152+
}
153+
154+
/**
155+
* Evaluate the JSON path expression against the supplied {@code content}
156+
* and assert that the resulting value is a {@link Number}.
157+
* @param content the JSON response content
158+
* @since 4.2.1
159+
*/
160+
public void assertValueIsNumber(String content) throws ParseException {
161+
Object value = assertExistsAndReturn(content);
162+
String reason = "Expected number at JSON path " + this.expression + " but found " + value;
163+
assertThat(reason, value, instanceOf(Number.class));
132164
}
133165

134166
/**
135-
* Apply the JSON path and assert the resulting value is an array.
167+
* Evaluate the JSON path expression against the supplied {@code content}
168+
* and assert that the resulting value is an array.
169+
* @param content the JSON response content
136170
*/
137-
public void assertValueIsArray(String responseContent) throws ParseException {
138-
Object actualValue = evaluateJsonPath(responseContent);
139-
assertTrue("No value for JSON path \"" + this.expression + "\"", actualValue != null);
140-
String reason = "Expected array at JSON path " + this.expression + " but found " + actualValue;
141-
assertTrue(reason, actualValue instanceof List);
171+
public void assertValueIsArray(String content) throws ParseException {
172+
Object value = assertExistsAndReturn(content);
173+
String reason = "Expected array for JSON path \"" + this.expression + "\" but found " + value;
174+
assertTrue(reason, value instanceof List);
142175
}
143176

144177
/**
145-
* Evaluate the JSON path and assert the resulting content exists.
178+
* Evaluate the JSON path expression against the supplied {@code content}
179+
* and assert that the resulting value is a {@link Map}.
180+
* @param content the JSON response content
181+
* @since 4.2.1
182+
*/
183+
public void assertValueIsMap(String content) throws ParseException {
184+
Object value = assertExistsAndReturn(content);
185+
String reason = "Expected map at JSON path " + this.expression + " but found " + value;
186+
assertThat(reason, value, instanceOf(Map.class));
187+
}
188+
189+
/**
190+
* Evaluate the JSON path expression against the supplied {@code content}
191+
* and assert that the resulting value exists.
192+
* @param content the JSON response content
146193
*/
147194
public void exists(String content) throws ParseException {
148-
Object value = evaluateJsonPath(content);
149-
String reason = "No value for JSON path " + this.expression;
150-
assertTrue(reason, value != null);
151-
if (List.class.isInstance(value)) {
152-
assertTrue(reason, !((List<?>) value).isEmpty());
153-
}
195+
assertExistsAndReturn(content);
154196
}
155197

156198
/**
157-
* Evaluate the JSON path and assert it doesn't point to any content.
199+
* Evaluate the JSON path expression against the supplied {@code content}
200+
* and assert that the resulting value is empty (i.e., that a match for
201+
* the JSON path expression does not exist in the supplied content).
202+
* @param content the JSON response content
158203
*/
159204
public void doesNotExist(String content) throws ParseException {
160205
Object value;
@@ -173,4 +218,30 @@ public void doesNotExist(String content) throws ParseException {
173218
}
174219
}
175220

221+
private Object evaluateJsonPath(String content) throws ParseException {
222+
String message = "No value for JSON path \"" + this.expression + "\", exception: ";
223+
try {
224+
return this.jsonPath.read(content);
225+
}
226+
catch (InvalidPathException ex) {
227+
throw new AssertionError(message + ex.getMessage());
228+
}
229+
catch (ArrayIndexOutOfBoundsException ex) {
230+
throw new AssertionError(message + ex.getMessage());
231+
}
232+
catch (IndexOutOfBoundsException ex) {
233+
throw new AssertionError(message + ex.getMessage());
234+
}
235+
}
236+
237+
private Object assertExistsAndReturn(String content) throws ParseException {
238+
Object value = evaluateJsonPath(content);
239+
String reason = "No value for JSON path \"" + this.expression + "\"";
240+
assertTrue(reason, value != null);
241+
if (List.class.isInstance(value)) {
242+
assertTrue(reason, !((List<?>) value).isEmpty());
243+
}
244+
return value;
245+
}
246+
176247
}

0 commit comments

Comments
 (0)