diff --git a/spring-test/src/main/java/org/springframework/test/util/JsonPathExpectationsHelper.java b/spring-test/src/main/java/org/springframework/test/util/JsonPathExpectationsHelper.java index e1d9d1615c..42c128fe3d 100644 --- a/spring-test/src/main/java/org/springframework/test/util/JsonPathExpectationsHelper.java +++ b/spring-test/src/main/java/org/springframework/test/util/JsonPathExpectationsHelper.java @@ -28,9 +28,11 @@ import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; -import static org.hamcrest.MatcherAssert.*; -import static org.hamcrest.core.IsInstanceOf.*; -import static org.springframework.test.util.AssertionErrors.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.springframework.test.util.AssertionErrors.assertEquals; +import static org.springframework.test.util.AssertionErrors.assertTrue; +import static org.springframework.test.util.AssertionErrors.fail; /** * A helper class for applying assertions via JSON path expressions. @@ -76,6 +78,21 @@ public class JsonPathExpectationsHelper { assertThat("JSON path \"" + this.expression + "\"", value, matcher); } + /** + * An overloaded variant of {@link #assertValue(String, Matcher)} that also + * accepts a target type for the resulting value. This can be useful for + * matching numbers reliably for example coercing an integer into a double. + * @param content the JSON content + * @param matcher the matcher with which to assert the result + * @param targetType a the expected type of the resulting value + * @since 5.0 + */ + @SuppressWarnings("unchecked") + public void assertValue(String content, Matcher matcher, Class targetType) throws ParseException { + T value = (T) evaluateJsonPath(content, targetType); + assertThat("JSON path \"" + this.expression + "\"", value, matcher); + } + /** * Evaluate the JSON path expression against the supplied {@code content} * and assert that the result is equal to the expected value. @@ -96,8 +113,9 @@ public class JsonPathExpectationsHelper { actualValue = actualValueList.get(0); } else if (actualValue != null && expectedValue != null) { - assertEquals("At JSON path \"" + this.expression + "\", type of value", - expectedValue.getClass().getName(), actualValue.getClass().getName()); + if (!actualValue.getClass().equals(expectedValue.getClass())) { + actualValue = evaluateJsonPath(content, expectedValue.getClass()); + } } assertEquals("JSON path \"" + this.expression + "\"", expectedValue, actualValue); } @@ -232,6 +250,16 @@ public class JsonPathExpectationsHelper { } } + private Object evaluateJsonPath(String content, Class targetType) throws ParseException { + String message = "No value at JSON path \"" + this.expression + "\", exception: "; + try { + return JsonPath.parse(content).read(this.expression, targetType); + } + catch (InvalidPathException | IndexOutOfBoundsException ex) { + throw new AssertionError(message + ex.getMessage()); + } + } + private Object assertExistsAndReturn(String content) throws ParseException { Object value = evaluateJsonPath(content); String reason = "No value at JSON path \"" + this.expression + "\""; diff --git a/spring-test/src/main/java/org/springframework/test/web/client/match/JsonPathRequestMatchers.java b/spring-test/src/main/java/org/springframework/test/web/client/match/JsonPathRequestMatchers.java index 2c3b7a99f9..1acb2c38e1 100644 --- a/spring-test/src/main/java/org/springframework/test/web/client/match/JsonPathRequestMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/client/match/JsonPathRequestMatchers.java @@ -69,6 +69,22 @@ public class JsonPathRequestMatchers { }; } + /** + * An overloaded variant of (@link {@link #value(Matcher)} that also + * accepts a target type for the resulting value that the matcher can work + * reliably against. This can be useful for matching numbers reliably for + * example coercing an integer into a double. + */ + public RequestMatcher value(final Matcher matcher, final Class targetType) { + return new AbstractJsonPathRequestMatcher() { + @Override + protected void matchInternal(MockClientHttpRequest request) throws IOException, ParseException { + String body = request.getBodyAsString(); + JsonPathRequestMatchers.this.jsonPathHelper.assertValue(body, matcher, targetType); + } + }; + } + /** * Evaluate the JSON path expression against the request content and * assert that the result is equal to the supplied value. diff --git a/spring-test/src/test/java/org/springframework/test/util/JsonPathExpectationsHelperTests.java b/spring-test/src/test/java/org/springframework/test/util/JsonPathExpectationsHelperTests.java index ba44e89487..e3b8d532fc 100644 --- a/spring-test/src/test/java/org/springframework/test/util/JsonPathExpectationsHelperTests.java +++ b/spring-test/src/test/java/org/springframework/test/util/JsonPathExpectationsHelperTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2004-2015 the original author or authors. + * Copyright 2004-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.core.Is.is; /** * Unit tests for {@link JsonPathExpectationsHelper}. @@ -222,11 +222,14 @@ public class JsonPathExpectationsHelperTests { new JsonPathExpectationsHelper("$.num").assertValue(CONTENT, 5); } - @Test - public void assertValueWithDifferentExpectedType() throws Exception { - exception.expect(AssertionError.class); - exception.expectMessage(equalTo("At JSON path \"$.num\", type of value expected: but was:")); - new JsonPathExpectationsHelper("$.num").assertValue(CONTENT, "5"); + @Test // SPR-14498 + public void assertValueWithNumberConversion() throws Exception { + new JsonPathExpectationsHelper("$.num").assertValue(CONTENT, 5.0); + } + + @Test // SPR-14498 + public void assertValueWithNumberConversionAndMatcher() throws Exception { + new JsonPathExpectationsHelper("$.num").assertValue(CONTENT, is(5.0), Double.class); } @Test