diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClient.java b/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClient.java index 39f17ba9e5b..1fc9f45bb32 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClient.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClient.java @@ -28,9 +28,13 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; import java.util.function.Function; +import com.jayway.jsonpath.Configuration; +import com.jayway.jsonpath.TypeRef; +import com.jayway.jsonpath.spi.mapper.MappingProvider; import org.jspecify.annotations.Nullable; import org.springframework.core.ParameterizedTypeReference; +import org.springframework.core.ResolvableType; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpRequest; @@ -486,7 +490,8 @@ class DefaultRestTestClient implements RestTestClient { @Override public JsonPathAssertions jsonPath(String expression) { - return new JsonPathAssertions(this, getBodyAsString(), expression, null); + Configuration config = JsonPathConfigurationProvider.getConfiguration(this.result); + return new JsonPathAssertions(this, getBodyAsString(), expression, config); } @Override @@ -540,4 +545,37 @@ class DefaultRestTestClient implements RestTestClient { } } + + private static class JsonPathConfigurationProvider { + + static Configuration getConfiguration(EntityExchangeResult result) { + Configuration config = Configuration.defaultConfiguration(); + JsonConverterDelegate delegate = result.getJsonConverterDelegate(); + return (delegate != null ? config.mappingProvider(new MessageConverterMappingProvider(delegate)) : config); + } + } + + + private record MessageConverterMappingProvider(JsonConverterDelegate delegate) implements MappingProvider { + + @Override + public T map(Object value, Class targetType, Configuration configuration) { + return mapToTargetType(value, ResolvableType.forClass(targetType)); + } + + @Override + public T map(Object value, TypeRef targetType, Configuration configuration) { + return mapToTargetType(value, ResolvableType.forType(targetType.getType())); + } + + private T mapToTargetType(Object value, ResolvableType targetType) { + try { + return delegate().map(value, targetType); + } + catch (IOException ex) { + throw new IllegalStateException("Failed to map " + value + " to " + targetType, ex); + } + } + } + } diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/client/JsonPathAssertionTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/client/JsonPathAssertionTests.java index 02af4e88e08..1e221233e43 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/client/JsonPathAssertionTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/client/JsonPathAssertionTests.java @@ -23,6 +23,7 @@ import java.util.Map; import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.Test; +import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.test.web.Person; @@ -106,6 +107,19 @@ class JsonPathAssertionTests { .jsonPath("$.performers[1].name").value(v -> MatcherAssert.assertThat(v, equalTo("Yehudi Menuhin"))); } + @Test + void valueConsumer() { + client.get().uri("/music/people") + .exchange() + .expectBody() + .jsonPath("$.composers[0].name").value( + String.class, + name -> assertThat(name).isEqualTo("Johann Sebastian Bach")) + .jsonPath("$.composers[0].name").value( + ParameterizedTypeReference.forType(String.class), + name -> assertThat(name).isEqualTo("Johann Sebastian Bach")); + } + @Test void hamcrestMatcher() { client.get().uri("/music/people")