Browse Source

Add JsonConverterDelegate

The JsonConverterDelegate interface replaces usages of
HttpMessageContentConverter to provides the flexibility to use either
message converters or WebFlux codecs.

HttpMessageContentConverter is deprecated, and replaced with a package
private copy (DefaultJsonConverterDelegate) in the
org.springframework.test.json package that is accessible through
a static method on JsonConverterDelegate.

See gh-35737
pull/35768/head
rstoyanchev 3 months ago
parent
commit
125002844e
  1. 20
      spring-test/src/main/java/org/springframework/test/http/HttpMessageContentConverter.java
  2. 25
      spring-test/src/main/java/org/springframework/test/json/AbstractJsonContentAssert.java
  3. 22
      spring-test/src/main/java/org/springframework/test/json/AbstractJsonValueAssert.java
  4. 151
      spring-test/src/main/java/org/springframework/test/json/DefaultJsonConverterDelegate.java
  5. 36
      spring-test/src/main/java/org/springframework/test/json/JsonContent.java
  6. 61
      spring-test/src/main/java/org/springframework/test/json/JsonConverterDelegate.java
  7. 8
      spring-test/src/main/java/org/springframework/test/json/JsonPathValueAssert.java
  8. 20
      spring-test/src/main/java/org/springframework/test/web/servlet/assertj/AbstractMockHttpServletResponseAssert.java
  9. 10
      spring-test/src/main/java/org/springframework/test/web/servlet/assertj/DefaultMvcTestResult.java
  10. 18
      spring-test/src/main/java/org/springframework/test/web/servlet/assertj/MockMvcTester.java
  11. 6
      spring-test/src/main/java/org/springframework/test/web/servlet/assertj/MvcTestResultAssert.java
  12. 14
      spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClient.java
  13. 16
      spring-test/src/main/java/org/springframework/test/web/servlet/client/ExchangeResult.java
  14. 2
      spring-test/src/main/java/org/springframework/test/web/servlet/client/assertj/RestTestClientResponseAssert.java
  15. 19
      spring-test/src/test/java/org/springframework/test/json/AbstractJsonContentAssertTests.java
  16. 68
      spring-test/src/test/java/org/springframework/test/json/DefaultJsonConverterDelegateTests.java
  17. 9
      spring-test/src/test/java/org/springframework/test/json/JsonContentTests.java
  18. 5
      spring-test/src/test/java/org/springframework/test/json/JsonPathValueAssertTests.java
  19. 3
      spring-test/src/test/java/org/springframework/test/web/servlet/assertj/AbstractMockHttpServletResponseAssertTests.java

20
spring-test/src/main/java/org/springframework/test/http/HttpMessageContentConverter.java

@ -18,11 +18,13 @@ package org.springframework.test.http;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpInputMessage;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.converter.GenericHttpMessageConverter; import org.springframework.http.converter.GenericHttpMessageConverter;
@ -31,6 +33,7 @@ import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.SmartHttpMessageConverter; import org.springframework.http.converter.SmartHttpMessageConverter;
import org.springframework.mock.http.MockHttpInputMessage; import org.springframework.mock.http.MockHttpInputMessage;
import org.springframework.mock.http.MockHttpOutputMessage; import org.springframework.mock.http.MockHttpOutputMessage;
import org.springframework.test.json.JsonConverterDelegate;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.function.SingletonSupplier; import org.springframework.util.function.SingletonSupplier;
@ -39,8 +42,10 @@ import org.springframework.util.function.SingletonSupplier;
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 6.2 * @since 6.2
* @deprecated in favor of static factory methods in {@link JsonConverterDelegate}
*/ */
public class HttpMessageContentConverter { @Deprecated(since = "7.0", forRemoval = true)
public class HttpMessageContentConverter implements JsonConverterDelegate {
private static final MediaType JSON = MediaType.APPLICATION_JSON; private static final MediaType JSON = MediaType.APPLICATION_JSON;
@ -69,6 +74,19 @@ public class HttpMessageContentConverter {
} }
@Override
public <T> T read(String content, ResolvableType targetType) throws IOException{
HttpInputMessage message = new MockHttpInputMessage(content.getBytes(StandardCharsets.UTF_8));
message.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
return convert(message, MediaType.APPLICATION_JSON, targetType);
}
@Override
public <T> T map(Object value, ResolvableType targetType) throws IOException {
return convertViaJson(value, targetType);
}
/** /**
* Convert the given {@link HttpInputMessage} whose content must match the * Convert the given {@link HttpInputMessage} whose content must match the
* given {@link MediaType} to the requested {@code targetType}. * given {@link MediaType} to the requested {@code targetType}.

25
spring-test/src/main/java/org/springframework/test/json/AbstractJsonContentAssert.java

@ -20,7 +20,6 @@ import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -42,11 +41,6 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.MediaType;
import org.springframework.mock.http.MockHttpInputMessage;
import org.springframework.test.http.HttpMessageContentConverter;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@ -77,7 +71,7 @@ public abstract class AbstractJsonContentAssert<SELF extends AbstractJsonContent
private static final Failures failures = Failures.instance(); private static final Failures failures = Failures.instance();
private final @Nullable HttpMessageContentConverter contentConverter; private final @Nullable JsonConverterDelegate converterDelegate;
private @Nullable Class<?> resourceLoadClass; private @Nullable Class<?> resourceLoadClass;
@ -92,7 +86,7 @@ public abstract class AbstractJsonContentAssert<SELF extends AbstractJsonContent
*/ */
protected AbstractJsonContentAssert(@Nullable JsonContent actual, Class<?> selfType) { protected AbstractJsonContentAssert(@Nullable JsonContent actual, Class<?> selfType) {
super(actual, selfType); super(actual, selfType);
this.contentConverter = (actual != null ? actual.getContentConverter() : null); this.converterDelegate = (actual != null ? actual.getJsonConverterDelegate() : null);
this.jsonLoader = new JsonLoader(null, null); this.jsonLoader = new JsonLoader(null, null);
as("JSON content"); as("JSON content");
} }
@ -131,13 +125,12 @@ public abstract class AbstractJsonContentAssert<SELF extends AbstractJsonContent
private <T> T convertToTargetType(Type targetType) { private <T> T convertToTargetType(Type targetType) {
String json = this.actual.getJson(); String json = this.actual.getJson();
if (this.contentConverter == null) { if (this.converterDelegate == null) {
throw new IllegalStateException( throw new IllegalStateException(
"No JSON message converter available to convert %s".formatted(json)); "No JSON message converter available to convert %s".formatted(json));
} }
try { try {
return this.contentConverter.convert(fromJson(json), MediaType.APPLICATION_JSON, return this.converterDelegate.read(json, ResolvableType.forType(targetType));
ResolvableType.forType(targetType));
} }
catch (Exception ex) { catch (Exception ex) {
throw failure(new ValueProcessingFailed(json, throw failure(new ValueProcessingFailed(json,
@ -146,12 +139,6 @@ public abstract class AbstractJsonContentAssert<SELF extends AbstractJsonContent
} }
} }
private HttpInputMessage fromJson(String json) {
MockHttpInputMessage inputMessage = new MockHttpInputMessage(json.getBytes(StandardCharsets.UTF_8));
inputMessage.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
return inputMessage;
}
// JsonPath support // JsonPath support
@ -163,7 +150,7 @@ public abstract class AbstractJsonContentAssert<SELF extends AbstractJsonContent
*/ */
public JsonPathValueAssert extractingPath(String path) { public JsonPathValueAssert extractingPath(String path) {
Object value = new JsonPathValue(path).getValue(); Object value = new JsonPathValue(path).getValue();
return new JsonPathValueAssert(value, path, this.contentConverter); return new JsonPathValueAssert(value, path, this.converterDelegate);
} }
/** /**
@ -174,7 +161,7 @@ public abstract class AbstractJsonContentAssert<SELF extends AbstractJsonContent
*/ */
public SELF hasPathSatisfying(String path, Consumer<AssertProvider<JsonPathValueAssert>> valueRequirements) { public SELF hasPathSatisfying(String path, Consumer<AssertProvider<JsonPathValueAssert>> valueRequirements) {
Object value = new JsonPathValue(path).assertHasPath(); Object value = new JsonPathValue(path).assertHasPath();
JsonPathValueAssert valueAssert = new JsonPathValueAssert(value, path, this.contentConverter); JsonPathValueAssert valueAssert = new JsonPathValueAssert(value, path, this.converterDelegate);
valueRequirements.accept(() -> valueAssert); valueRequirements.accept(() -> valueAssert);
return this.myself; return this.myself;
} }

22
spring-test/src/main/java/org/springframework/test/json/AbstractJsonValueAssert.java

@ -35,7 +35,6 @@ import org.jspecify.annotations.Nullable;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.http.converter.GenericHttpMessageConverter; import org.springframework.http.converter.GenericHttpMessageConverter;
import org.springframework.test.http.HttpMessageContentConverter;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -64,14 +63,23 @@ public abstract class AbstractJsonValueAssert<SELF extends AbstractJsonValueAsse
private final Failures failures = Failures.instance(); private final Failures failures = Failures.instance();
private final @Nullable HttpMessageContentConverter contentConverter; private final @Nullable JsonConverterDelegate converterDelegate;
protected AbstractJsonValueAssert(@Nullable Object actual, Class<?> selfType, protected AbstractJsonValueAssert(
@Nullable HttpMessageContentConverter contentConverter) { @Nullable Object actual, Class<?> selfType, @Nullable JsonConverterDelegate converter) {
super(actual, selfType); super(actual, selfType);
this.contentConverter = contentConverter; this.converterDelegate = converter;
}
@SuppressWarnings("removal")
@Deprecated(since = "7.0", forRemoval = true)
protected AbstractJsonValueAssert(
@Nullable Object actual, Class<?> selfType,
org.springframework.test.http.@Nullable HttpMessageContentConverter converter) {
this(actual, selfType, (JsonConverterDelegate) converter);
} }
@ -196,12 +204,12 @@ public abstract class AbstractJsonValueAssert<SELF extends AbstractJsonValueAsse
} }
private <T> T convertToTargetType(Type targetType) { private <T> T convertToTargetType(Type targetType) {
if (this.contentConverter == null) { if (this.converterDelegate == null) {
throw new IllegalStateException( throw new IllegalStateException(
"No JSON message converter available to convert %s".formatted(actualToString())); "No JSON message converter available to convert %s".formatted(actualToString()));
} }
try { try {
return this.contentConverter.convertViaJson(this.actual, ResolvableType.forType(targetType)); return this.converterDelegate.map(this.actual, ResolvableType.forType(targetType));
} }
catch (Exception ex) { catch (Exception ex) {
throw valueProcessingFailed("To convert successfully to:%n %s%nBut it failed:%n %s%n" throw valueProcessingFailed("To convert successfully to:%n %s%nBut it failed:%n %s%n"

151
spring-test/src/main/java/org/springframework/test/json/DefaultJsonConverterDelegate.java

@ -0,0 +1,151 @@
/*
* Copyright 2002-present 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.json;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.stream.StreamSupport;
import org.springframework.core.ResolvableType;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.GenericHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.SmartHttpMessageConverter;
import org.springframework.mock.http.MockHttpInputMessage;
import org.springframework.mock.http.MockHttpOutputMessage;
import org.springframework.util.Assert;
import org.springframework.util.function.SingletonSupplier;
/**
* Default {@link JsonConverterDelegate} based on {@link HttpMessageConverter}s.
*
* @author Stephane Nicoll
* @author Rossen Stoyanchev
* @since 7.0
*/
final class DefaultJsonConverterDelegate implements JsonConverterDelegate {
private static final MediaType JSON = MediaType.APPLICATION_JSON;
private final List<HttpMessageConverter<?>> messageConverters;
DefaultJsonConverterDelegate(Iterable<HttpMessageConverter<?>> messageConverters) {
this.messageConverters = StreamSupport.stream(messageConverters.spliterator(), false).toList();
Assert.notEmpty(this.messageConverters, "At least one message converter needs to be specified");
}
@Override
public <T> T read(String content, ResolvableType targetType) throws IOException{
HttpInputMessage message = new MockHttpInputMessage(content.getBytes(StandardCharsets.UTF_8));
message.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
return read(message, MediaType.APPLICATION_JSON, targetType);
}
/**
* Convert the given {@link HttpInputMessage} whose content must match the
* given {@link MediaType} to the requested {@code targetType}.
* @param message an input message
* @param mediaType the media type of the input
* @param targetType the target type
* @param <T> the converted object type
* @return a value of the given {@code targetType}
*/
@SuppressWarnings("unchecked")
<T> T read(HttpInputMessage message, MediaType mediaType, ResolvableType targetType)
throws IOException, HttpMessageNotReadableException {
Class<?> contextClass = targetType.getRawClass();
SingletonSupplier<Type> javaType = SingletonSupplier.of(targetType::getType);
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
if (messageConverter instanceof GenericHttpMessageConverter<?> genericMessageConverter) {
Type type = javaType.obtain();
if (genericMessageConverter.canRead(type, contextClass, mediaType)) {
return (T) genericMessageConverter.read(type, contextClass, message);
}
}
else if (messageConverter instanceof SmartHttpMessageConverter<?> smartMessageConverter) {
if (smartMessageConverter.canRead(targetType, mediaType)) {
return (T) smartMessageConverter.read(targetType, message, null);
}
}
else {
Class<?> targetClass = (contextClass != null ? contextClass : Object.class);
if (messageConverter.canRead(targetClass, mediaType)) {
HttpMessageConverter<T> simpleMessageConverter = (HttpMessageConverter<T>) messageConverter;
Class<? extends T> clazz = (Class<? extends T>) targetClass;
return simpleMessageConverter.read(clazz, message);
}
}
}
throw new IllegalStateException("No converter found to read [%s] to [%s]".formatted(mediaType, targetType));
}
/**
* Convert the given raw value to the given {@code targetType} by writing
* it first to JSON and reading it back.
* @param value the value to convert
* @param targetType the target type
* @param <T> the converted object type
* @return a value of the given {@code targetType}
*/
@Override
public <T> T map(Object value, ResolvableType targetType) throws IOException {
MockHttpOutputMessage outputMessage = writeToJson(value, ResolvableType.forInstance(value));
return read(fromHttpOutputMessage(outputMessage), JSON, targetType);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private MockHttpOutputMessage writeToJson(Object value, ResolvableType valueType) throws IOException {
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
Class<?> valueClass = value.getClass();
SingletonSupplier<Type> javaType = SingletonSupplier.of(valueType::getType);
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
if (messageConverter instanceof GenericHttpMessageConverter genericMessageConverter) {
Type type = javaType.obtain();
if (genericMessageConverter.canWrite(type, valueClass, JSON)) {
genericMessageConverter.write(value, type, JSON, outputMessage);
return outputMessage;
}
}
else if (messageConverter instanceof SmartHttpMessageConverter smartMessageConverter) {
if (smartMessageConverter.canWrite(valueType, valueClass, JSON)) {
smartMessageConverter.write(value, valueType, JSON, outputMessage, null);
return outputMessage;
}
}
else if (messageConverter.canWrite(valueClass, JSON)) {
((HttpMessageConverter<Object>) messageConverter).write(value, JSON, outputMessage);
return outputMessage;
}
}
throw new IllegalStateException("No converter found to convert [%s] to JSON".formatted(valueType));
}
private static HttpInputMessage fromHttpOutputMessage(MockHttpOutputMessage message) {
MockHttpInputMessage inputMessage = new MockHttpInputMessage(message.getBodyAsBytes());
inputMessage.getHeaders().addAll(message.getHeaders());
return inputMessage;
}
}

36
spring-test/src/main/java/org/springframework/test/json/JsonContent.java

@ -34,19 +34,32 @@ public final class JsonContent implements AssertProvider<JsonContentAssert> {
private final String json; private final String json;
private final @Nullable HttpMessageContentConverter contentConverter; private final @Nullable JsonConverterDelegate converterDelegate;
/** /**
* Create a new {@code JsonContent} instance with the message converter to * Create a new {@code JsonContent} instance with the message converter to
* use to deserialize content. * use to deserialize content.
* @param json the actual JSON content * @param json the actual JSON content
* @param contentConverter the content converter to use * @param converterDelegate the content converter to use
*/ */
public JsonContent(String json, @Nullable HttpMessageContentConverter contentConverter) { public JsonContent(String json, @Nullable JsonConverterDelegate converterDelegate) {
Assert.notNull(json, "JSON must not be null"); Assert.notNull(json, "JSON must not be null");
this.json = json; this.json = json;
this.contentConverter = contentConverter; this.converterDelegate = converterDelegate;
}
/**
* Create a new {@code JsonContent} instance with the message converter to
* use to deserialize content.
* @param json the actual JSON content
* @param converter the content converter to use
* @deprecated in favour of {@link #JsonContent(String, JsonConverterDelegate)}
*/
@SuppressWarnings("removal")
@Deprecated(since = "7.0", forRemoval = true)
public JsonContent(String json, @Nullable HttpMessageContentConverter converter) {
this(json, (JsonConverterDelegate) converter);
} }
/** /**
@ -54,7 +67,7 @@ public final class JsonContent implements AssertProvider<JsonContentAssert> {
* @param json the actual JSON content * @param json the actual JSON content
*/ */
public JsonContent(String json) { public JsonContent(String json) {
this(json, null); this(json, (JsonConverterDelegate) null);
} }
@ -74,11 +87,22 @@ public final class JsonContent implements AssertProvider<JsonContentAssert> {
return this.json; return this.json;
} }
/**
* Return the {@link JsonConverterDelegate} to use to decode JSON content.
* @since 7.0
*/
public @Nullable JsonConverterDelegate getJsonConverterDelegate() {
return this.converterDelegate;
}
/** /**
* Return the {@link HttpMessageContentConverter} to use to deserialize content. * Return the {@link HttpMessageContentConverter} to use to deserialize content.
* @deprecated in favour of {@link #getJsonConverterDelegate()}
*/ */
@SuppressWarnings("removal")
@Deprecated(since = "7.0", forRemoval = true)
@Nullable HttpMessageContentConverter getContentConverter() { @Nullable HttpMessageContentConverter getContentConverter() {
return this.contentConverter; return (this.converterDelegate instanceof HttpMessageContentConverter cc ? cc : null);
} }
@Override @Override

61
spring-test/src/main/java/org/springframework/test/json/JsonConverterDelegate.java

@ -0,0 +1,61 @@
/*
* Copyright 2002-present 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.json;
import java.io.IOException;
import org.springframework.core.ResolvableType;
import org.springframework.http.converter.HttpMessageConverter;
/**
* Delegate to abstract JSON type conversion in AssertJ support clases.
*
* @author Rossen Stoyanchev
* @since 7.0
*/
public interface JsonConverterDelegate {
/**
* Convert JSON content to the given {@code targetType}.
* @param content the JSON content
* @param targetType the target type
* @return the decoded object
* @param <T> the target type
*/
<T> T read(String content, ResolvableType targetType) throws IOException;
/**
* Map the given Object value to the given {@code targetType}, via
* serialization and deserialization to and from JSON. This is useful for
* mapping generic maps and lists to higher level Objects.
* @param value the value to map
* @param targetType the target tyep
* @return the decoded object
* @param <T> the target type
*/
<T> T map(Object value, ResolvableType targetType) throws IOException;
/**
* Create a {@link JsonConverterDelegate} from message converters.
* @param candidates the candidates
*/
static JsonConverterDelegate of(Iterable<HttpMessageConverter<?>> candidates) {
return new DefaultJsonConverterDelegate(candidates);
}
}

8
spring-test/src/main/java/org/springframework/test/json/JsonPathValueAssert.java

@ -19,8 +19,6 @@ package org.springframework.test.json;
import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.JsonPath;
import org.jspecify.annotations.Nullable; import org.jspecify.annotations.Nullable;
import org.springframework.test.http.HttpMessageContentConverter;
/** /**
* AssertJ {@linkplain org.assertj.core.api.Assert assertions} that can be applied * AssertJ {@linkplain org.assertj.core.api.Assert assertions} that can be applied
* to a JSON value produced by evaluating a {@linkplain JsonPath JSON path} * to a JSON value produced by evaluating a {@linkplain JsonPath JSON path}
@ -34,10 +32,8 @@ public class JsonPathValueAssert extends AbstractJsonValueAssert<JsonPathValueAs
private final String expression; private final String expression;
JsonPathValueAssert(@Nullable Object actual, String expression, JsonPathValueAssert(@Nullable Object actual, String expression, @Nullable JsonConverterDelegate converter) {
@Nullable HttpMessageContentConverter contentConverter) { super(actual, JsonPathValueAssert.class, converter);
super(actual, JsonPathValueAssert.class, contentConverter);
this.expression = expression; this.expression = expression;
} }

20
spring-test/src/main/java/org/springframework/test/web/servlet/assertj/AbstractMockHttpServletResponseAssert.java

@ -26,10 +26,10 @@ import org.assertj.core.api.StringAssert;
import org.jspecify.annotations.Nullable; import org.jspecify.annotations.Nullable;
import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.http.HttpMessageContentConverter;
import org.springframework.test.json.AbstractJsonContentAssert; import org.springframework.test.json.AbstractJsonContentAssert;
import org.springframework.test.json.JsonContent; import org.springframework.test.json.JsonContent;
import org.springframework.test.json.JsonContentAssert; import org.springframework.test.json.JsonContentAssert;
import org.springframework.test.json.JsonConverterDelegate;
import org.springframework.test.web.UriAssert; import org.springframework.test.web.UriAssert;
/** /**
@ -44,13 +44,23 @@ import org.springframework.test.web.UriAssert;
public abstract class AbstractMockHttpServletResponseAssert<SELF extends AbstractMockHttpServletResponseAssert<SELF, ACTUAL>, ACTUAL> public abstract class AbstractMockHttpServletResponseAssert<SELF extends AbstractMockHttpServletResponseAssert<SELF, ACTUAL>, ACTUAL>
extends AbstractHttpServletResponseAssert<MockHttpServletResponse, SELF, ACTUAL> { extends AbstractHttpServletResponseAssert<MockHttpServletResponse, SELF, ACTUAL> {
private final @Nullable HttpMessageContentConverter contentConverter; private final @Nullable JsonConverterDelegate converterDelegate;
protected AbstractMockHttpServletResponseAssert( protected AbstractMockHttpServletResponseAssert(
@Nullable HttpMessageContentConverter contentConverter, ACTUAL actual, Class<?> selfType) { @Nullable JsonConverterDelegate converterDelegate, ACTUAL actual, Class<?> selfType) {
super(actual, selfType); super(actual, selfType);
this.contentConverter = contentConverter; this.converterDelegate = converterDelegate;
}
@SuppressWarnings("removal")
@Deprecated(since = "7.0", forRemoval = true)
protected AbstractMockHttpServletResponseAssert(
org.springframework.test.http.@Nullable HttpMessageContentConverter converter,
ACTUAL actual, Class<?> selfType) {
this((JsonConverterDelegate) converter, actual, selfType);
} }
@ -93,7 +103,7 @@ public abstract class AbstractMockHttpServletResponseAssert<SELF extends Abstrac
* </code></pre> * </code></pre>
*/ */
public AbstractJsonContentAssert<?> bodyJson() { public AbstractJsonContentAssert<?> bodyJson() {
return new JsonContentAssert(new JsonContent(readBody(), this.contentConverter)); return new JsonContentAssert(new JsonContent(readBody(), this.converterDelegate));
} }
private String readBody() { private String readBody() {

10
spring-test/src/main/java/org/springframework/test/web/servlet/assertj/DefaultMvcTestResult.java

@ -18,7 +18,7 @@ package org.springframework.test.web.servlet.assertj;
import org.jspecify.annotations.Nullable; import org.jspecify.annotations.Nullable;
import org.springframework.test.http.HttpMessageContentConverter; import org.springframework.test.json.JsonConverterDelegate;
import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.MvcResult;
/** /**
@ -33,15 +33,15 @@ final class DefaultMvcTestResult implements MvcTestResult {
private final @Nullable Exception unresolvedException; private final @Nullable Exception unresolvedException;
private final @Nullable HttpMessageContentConverter contentConverter; private final @Nullable JsonConverterDelegate converterDelegate;
DefaultMvcTestResult(@Nullable MvcResult mvcResult, @Nullable Exception unresolvedException, DefaultMvcTestResult(@Nullable MvcResult mvcResult, @Nullable Exception unresolvedException,
@Nullable HttpMessageContentConverter contentConverter) { @Nullable JsonConverterDelegate converterDelegate) {
this.mvcResult = mvcResult; this.mvcResult = mvcResult;
this.unresolvedException = unresolvedException; this.unresolvedException = unresolvedException;
this.contentConverter = contentConverter; this.converterDelegate = converterDelegate;
} }
@ -70,7 +70,7 @@ final class DefaultMvcTestResult implements MvcTestResult {
*/ */
@Override @Override
public MvcTestResultAssert assertThat() { public MvcTestResultAssert assertThat() {
return new MvcTestResultAssert(this, this.contentConverter); return new MvcTestResultAssert(this, this.converterDelegate);
} }
} }

18
spring-test/src/main/java/org/springframework/test/web/servlet/assertj/MockMvcTester.java

@ -30,7 +30,7 @@ import org.springframework.http.HttpMethod;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockMultipartHttpServletRequest; import org.springframework.mock.web.MockMultipartHttpServletRequest;
import org.springframework.test.http.HttpMessageContentConverter; import org.springframework.test.json.JsonConverterDelegate;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder; import org.springframework.test.web.servlet.RequestBuilder;
@ -132,13 +132,13 @@ public final class MockMvcTester {
private final MockMvc mockMvc; private final MockMvc mockMvc;
private final @Nullable HttpMessageContentConverter contentConverter; private final @Nullable JsonConverterDelegate converterDelegate;
private MockMvcTester(MockMvc mockMvc, @Nullable HttpMessageContentConverter contentConverter) { private MockMvcTester(MockMvc mockMvc, @Nullable JsonConverterDelegate converter) {
Assert.notNull(mockMvc, "mockMVC should not be null"); Assert.notNull(mockMvc, "mockMVC should not be null");
this.mockMvc = mockMvc; this.mockMvc = mockMvc;
this.contentConverter = contentConverter; this.converterDelegate = converter;
} }
/** /**
@ -232,7 +232,7 @@ public final class MockMvcTester {
* @return a new instance using the specified converters * @return a new instance using the specified converters
*/ */
public MockMvcTester withHttpMessageConverters(Iterable<HttpMessageConverter<?>> httpMessageConverters) { public MockMvcTester withHttpMessageConverters(Iterable<HttpMessageConverter<?>> httpMessageConverters) {
return new MockMvcTester(this.mockMvc, HttpMessageContentConverter.of(httpMessageConverters)); return new MockMvcTester(this.mockMvc, JsonConverterDelegate.of(httpMessageConverters));
} }
/** /**
@ -374,10 +374,10 @@ public final class MockMvcTester {
public MvcTestResult perform(RequestBuilder requestBuilder) { public MvcTestResult perform(RequestBuilder requestBuilder) {
Object result = getMvcResultOrFailure(requestBuilder); Object result = getMvcResultOrFailure(requestBuilder);
if (result instanceof MvcResult mvcResult) { if (result instanceof MvcResult mvcResult) {
return new DefaultMvcTestResult(mvcResult, null, this.contentConverter); return new DefaultMvcTestResult(mvcResult, null, this.converterDelegate);
} }
else { else {
return new DefaultMvcTestResult(null, (Exception) result, this.contentConverter); return new DefaultMvcTestResult(null, (Exception) result, this.converterDelegate);
} }
} }
@ -483,7 +483,7 @@ public final class MockMvcTester {
@Override @Override
public MvcTestResultAssert assertThat() { public MvcTestResultAssert assertThat() {
return new MvcTestResultAssert(exchange(), MockMvcTester.this.contentConverter); return new MvcTestResultAssert(exchange(), MockMvcTester.this.converterDelegate);
} }
} }
@ -541,7 +541,7 @@ public final class MockMvcTester {
@Override @Override
public MvcTestResultAssert assertThat() { public MvcTestResultAssert assertThat() {
return new MvcTestResultAssert(exchange(), MockMvcTester.this.contentConverter); return new MvcTestResultAssert(exchange(), MockMvcTester.this.converterDelegate);
} }
} }

6
spring-test/src/main/java/org/springframework/test/web/servlet/assertj/MvcTestResultAssert.java

@ -34,7 +34,7 @@ import org.jspecify.annotations.Nullable;
import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.http.HttpMessageContentConverter; import org.springframework.test.json.JsonConverterDelegate;
import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultHandler; import org.springframework.test.web.servlet.ResultHandler;
import org.springframework.test.web.servlet.ResultMatcher; import org.springframework.test.web.servlet.ResultMatcher;
@ -51,8 +51,8 @@ import org.springframework.web.servlet.ModelAndView;
*/ */
public class MvcTestResultAssert extends AbstractMockHttpServletResponseAssert<MvcTestResultAssert, MvcTestResult> { public class MvcTestResultAssert extends AbstractMockHttpServletResponseAssert<MvcTestResultAssert, MvcTestResult> {
MvcTestResultAssert(MvcTestResult actual, @Nullable HttpMessageContentConverter contentConverter) { MvcTestResultAssert(MvcTestResult actual, @Nullable JsonConverterDelegate converterDelegate) {
super(contentConverter, actual, MvcTestResultAssert.class); super(converterDelegate, actual, MvcTestResultAssert.class);
} }
@Override @Override

14
spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClient.java

@ -39,10 +39,10 @@ import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.converter.HttpMessageConverters; import org.springframework.http.converter.HttpMessageConverters;
import org.springframework.test.http.HttpMessageContentConverter;
import org.springframework.test.json.JsonAssert; import org.springframework.test.json.JsonAssert;
import org.springframework.test.json.JsonComparator; import org.springframework.test.json.JsonComparator;
import org.springframework.test.json.JsonCompareMode; import org.springframework.test.json.JsonCompareMode;
import org.springframework.test.json.JsonConverterDelegate;
import org.springframework.test.util.AssertionErrors; import org.springframework.test.util.AssertionErrors;
import org.springframework.test.util.ExceptionCollector; import org.springframework.test.util.ExceptionCollector;
import org.springframework.test.util.XmlExpectationsHelper; import org.springframework.test.util.XmlExpectationsHelper;
@ -69,7 +69,7 @@ class DefaultRestTestClient implements RestTestClient {
private final DefaultRestTestClientBuilder<?> restTestClientBuilder; private final DefaultRestTestClientBuilder<?> restTestClientBuilder;
private final @Nullable HttpMessageContentConverter messageContentConverter; private final @Nullable JsonConverterDelegate converterDelegate;
private final AtomicLong requestIndex = new AtomicLong(); private final AtomicLong requestIndex = new AtomicLong();
@ -81,7 +81,7 @@ class DefaultRestTestClient implements RestTestClient {
this.restClient = builder.requestInterceptor(this.wiretapInterceptor).build(); this.restClient = builder.requestInterceptor(this.wiretapInterceptor).build();
this.entityResultConsumer = entityResultConsumer; this.entityResultConsumer = entityResultConsumer;
this.restTestClientBuilder = restTestClientBuilder; this.restTestClientBuilder = restTestClientBuilder;
this.messageContentConverter = new ConverterCallback(this.restClient).getConverter(); this.converterDelegate = new ConverterCallback(this.restClient).getConverter();
} }
@ -138,20 +138,20 @@ class DefaultRestTestClient implements RestTestClient {
private static class ConverterCallback { private static class ConverterCallback {
private @Nullable HttpMessageContentConverter converter; private @Nullable JsonConverterDelegate converter;
ConverterCallback(RestClient client) { ConverterCallback(RestClient client) {
client.mutate() client.mutate()
.configureMessageConverters(convertersBuilder -> { .configureMessageConverters(convertersBuilder -> {
HttpMessageConverters converters = convertersBuilder.build(); HttpMessageConverters converters = convertersBuilder.build();
if (converters.iterator().hasNext()) { if (converters.iterator().hasNext()) {
this.converter = HttpMessageContentConverter.of(converters); this.converter = JsonConverterDelegate.of(converters);
} }
}) })
.build(); .build();
} }
public @Nullable HttpMessageContentConverter getConverter() { public @Nullable JsonConverterDelegate getConverter() {
return this.converter; return this.converter;
} }
} }
@ -290,7 +290,7 @@ class DefaultRestTestClient implements RestTestClient {
(request, response) -> { (request, response) -> {
byte[] requestBody = wiretapInterceptor.getRequestContent(this.requestId); byte[] requestBody = wiretapInterceptor.getRequestContent(this.requestId);
return new ExchangeResult( return new ExchangeResult(
request, response, this.uriTemplate, requestBody, messageContentConverter); request, response, this.uriTemplate, requestBody, converterDelegate);
}, false), }, false),
DefaultRestTestClient.this.entityResultConsumer); DefaultRestTestClient.this.entityResultConsumer);
} }

16
spring-test/src/main/java/org/springframework/test/web/servlet/client/ExchangeResult.java

@ -38,7 +38,7 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode; import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.test.http.HttpMessageContentConverter; import org.springframework.test.json.JsonConverterDelegate;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
@ -75,7 +75,7 @@ public class ExchangeResult {
private final byte[] requestBody; private final byte[] requestBody;
private final @Nullable HttpMessageContentConverter messageContentConverter; private final @Nullable JsonConverterDelegate converterDelegate;
/** Ensure single logging; for example, for expectAll. */ /** Ensure single logging; for example, for expectAll. */
private boolean diagnosticsLogged; private boolean diagnosticsLogged;
@ -83,7 +83,7 @@ public class ExchangeResult {
ExchangeResult( ExchangeResult(
HttpRequest request, ConvertibleClientHttpResponse response, @Nullable String uriTemplate, HttpRequest request, ConvertibleClientHttpResponse response, @Nullable String uriTemplate,
byte[] requestBody, @Nullable HttpMessageContentConverter messageContentConverter) { byte[] requestBody, @Nullable JsonConverterDelegate converter) {
Assert.notNull(request, "HttpRequest must not be null"); Assert.notNull(request, "HttpRequest must not be null");
Assert.notNull(response, "ClientHttpResponse must not be null"); Assert.notNull(response, "ClientHttpResponse must not be null");
@ -91,11 +91,11 @@ public class ExchangeResult {
this.clientResponse = response; this.clientResponse = response;
this.uriTemplate = uriTemplate; this.uriTemplate = uriTemplate;
this.requestBody = requestBody; this.requestBody = requestBody;
this.messageContentConverter = messageContentConverter; this.converterDelegate = converter;
} }
ExchangeResult(ExchangeResult result) { ExchangeResult(ExchangeResult result) {
this(result.request, result.clientResponse, result.uriTemplate, result.requestBody, result.messageContentConverter); this(result.request, result.clientResponse, result.uriTemplate, result.requestBody, result.converterDelegate);
this.diagnosticsLogged = result.diagnosticsLogged; this.diagnosticsLogged = result.diagnosticsLogged;
} }
@ -202,11 +202,11 @@ public class ExchangeResult {
} }
/** /**
* Return a content converter that delegates to the configured HTTP message converters. * Return a {@link JsonConverterDelegate} based on the configured HTTP message converters.
* Mainly for internal use from AssertJ support. * Mainly for internal use from AssertJ support.
*/ */
public @Nullable HttpMessageContentConverter getMessageContentConverter() { public @Nullable JsonConverterDelegate getConverterDelegate() {
return this.messageContentConverter; return this.converterDelegate;
} }
/** /**

2
spring-test/src/main/java/org/springframework/test/web/servlet/client/assertj/RestTestClientResponseAssert.java

@ -342,7 +342,7 @@ public class RestTestClientResponseAssert
* </code></pre> * </code></pre>
*/ */
public AbstractJsonContentAssert<?> bodyJson() { public AbstractJsonContentAssert<?> bodyJson() {
return new JsonContentAssert(new JsonContent(readBody(), getExchangeResult().getMessageContentConverter())); return new JsonContentAssert(new JsonContent(readBody(), getExchangeResult().getConverterDelegate()));
} }
private String readBody() { private String readBody() {

19
spring-test/src/test/java/org/springframework/test/json/AbstractJsonContentAssertTests.java

@ -53,7 +53,6 @@ import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter; import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
import org.springframework.test.http.HttpMessageContentConverter;
import org.springframework.util.FileCopyUtils; import org.springframework.util.FileCopyUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -85,8 +84,8 @@ class AbstractJsonContentAssertTests {
private static final String DIFFERENT = loadJson("different.json"); private static final String DIFFERENT = loadJson("different.json");
private static final HttpMessageContentConverter jsonContentConverter = HttpMessageContentConverter.of( private static final JsonConverterDelegate jsonContentConverter =
new JacksonJsonHttpMessageConverter(new JsonMapper())); JsonConverterDelegate.of(List.of(new JacksonJsonHttpMessageConverter(new JsonMapper())));
private static final JsonComparator comparator = JsonAssert.comparator(JsonCompareMode.LENIENT); private static final JsonComparator comparator = JsonAssert.comparator(JsonCompareMode.LENIENT);
@ -120,10 +119,10 @@ class AbstractJsonContentAssertTests {
.hasFamilyMember("Homer"); .hasFamilyMember("Homer");
} }
private AssertProvider<AbstractJsonContentAssert<?>> forJson(@Nullable String json, private AssertProvider<AbstractJsonContentAssert<?>> forJson(
@Nullable HttpMessageContentConverter jsonContentConverter) { @Nullable String json, @Nullable JsonConverterDelegate converter) {
return () -> new TestJsonContentAssert(json, jsonContentConverter); return () -> new TestJsonContentAssert(json, converter);
} }
private static class FamilyAssertFactory extends InstanceOfAssertFactory<Family, FamilyAssert> { private static class FamilyAssertFactory extends InstanceOfAssertFactory<Family, FamilyAssert> {
@ -386,8 +385,8 @@ class AbstractJsonContentAssertTests {
return () -> new TestJsonContentAssert(json, null); return () -> new TestJsonContentAssert(json, null);
} }
private AssertProvider<AbstractJsonContentAssert<?>> forJson(@Nullable String json, HttpMessageContentConverter jsonContentConverter) { private AssertProvider<AbstractJsonContentAssert<?>> forJson(@Nullable String json, JsonConverterDelegate converter) {
return () -> new TestJsonContentAssert(json, jsonContentConverter); return () -> new TestJsonContentAssert(json, converter);
} }
} }
@ -886,8 +885,8 @@ class AbstractJsonContentAssertTests {
private static class TestJsonContentAssert extends AbstractJsonContentAssert<TestJsonContentAssert> { private static class TestJsonContentAssert extends AbstractJsonContentAssert<TestJsonContentAssert> {
public TestJsonContentAssert(@Nullable String json, @Nullable HttpMessageContentConverter jsonContentConverter) { public TestJsonContentAssert(@Nullable String json, @Nullable JsonConverterDelegate converter) {
super((json != null ? new JsonContent(json, jsonContentConverter) : null), TestJsonContentAssert.class); super((json != null ? new JsonContent(json, converter) : null), TestJsonContentAssert.class);
} }
} }

68
spring-test/src/test/java/org/springframework/test/http/HttpMessageContentConverterTests.java → spring-test/src/test/java/org/springframework/test/json/DefaultJsonConverterDelegateTests.java

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.test.http; package org.springframework.test.json;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -46,11 +46,11 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.verifyNoInteractions;
/** /**
* Tests for {@link HttpMessageContentConverter}. * Tests for {@link DefaultJsonConverterDelegate}.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */
class HttpMessageContentConverterTests { class DefaultJsonConverterDelegateTests {
private static final MediaType JSON = MediaType.APPLICATION_JSON; private static final MediaType JSON = MediaType.APPLICATION_JSON;
@ -58,17 +58,18 @@ class HttpMessageContentConverterTests {
private static final JacksonJsonHttpMessageConverter jacksonMessageConverter = new JacksonJsonHttpMessageConverter(); private static final JacksonJsonHttpMessageConverter jacksonMessageConverter = new JacksonJsonHttpMessageConverter();
@Test @Test
void createInstanceWithEmptyIterable() { void createInstanceWithEmptyIterable() {
assertThatIllegalArgumentException() assertThatIllegalArgumentException()
.isThrownBy(() -> HttpMessageContentConverter.of(List.of())) .isThrownBy(() -> new DefaultJsonConverterDelegate(List.of()))
.withMessage("At least one message converter needs to be specified"); .withMessage("At least one message converter needs to be specified");
} }
@Test @Test
void createInstanceWithEmptyVarArg() { void createInstanceWithEmptyVarArg() {
assertThatIllegalArgumentException() assertThatIllegalArgumentException()
.isThrownBy(HttpMessageContentConverter::of) .isThrownBy(() -> new DefaultJsonConverterDelegate(List.of()))
.withMessage("At least one message converter needs to be specified"); .withMessage("At least one message converter needs to be specified");
} }
@ -79,9 +80,9 @@ class HttpMessageContentConverterTests {
listOfIntegers, JSON, message, List.of(1, 2, 3)); listOfIntegers, JSON, message, List.of(1, 2, 3));
SmartHttpMessageConverter<?> secondConverter = mockSmartConverterForRead( SmartHttpMessageConverter<?> secondConverter = mockSmartConverterForRead(
listOfIntegers, JSON, message, List.of(3, 2, 1)); listOfIntegers, JSON, message, List.of(3, 2, 1));
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of( DefaultJsonConverterDelegate converter =
List.of(firstConverter, secondConverter)); new DefaultJsonConverterDelegate(List.of(firstConverter, secondConverter));
List<Integer> data = contentConverter.convert(message, JSON, listOfIntegers); List<Integer> data = converter.read(message, JSON, listOfIntegers);
assertThat(data).containsExactly(1, 2, 3); assertThat(data).containsExactly(1, 2, 3);
verify(firstConverter).canRead(listOfIntegers, JSON); verify(firstConverter).canRead(listOfIntegers, JSON);
verifyNoInteractions(secondConverter); verifyNoInteractions(secondConverter);
@ -90,9 +91,9 @@ class HttpMessageContentConverterTests {
@Test @Test
void convertInvokesGenericHttpMessageConverter() throws IOException { void convertInvokesGenericHttpMessageConverter() throws IOException {
GenericHttpMessageConverter<?> firstConverter = mock(GenericHttpMessageConverter.class); GenericHttpMessageConverter<?> firstConverter = mock(GenericHttpMessageConverter.class);
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of( DefaultJsonConverterDelegate converter =
List.of(firstConverter, jacksonMessageConverter)); new DefaultJsonConverterDelegate(List.of(firstConverter, jacksonMessageConverter));
List<Integer> data = contentConverter.convert(createMessage("[2,3,4]"), JSON, listOfIntegers); List<Integer> data = converter.read(createMessage("[2,3,4]"), JSON, listOfIntegers);
assertThat(data).containsExactly(2, 3, 4); assertThat(data).containsExactly(2, 3, 4);
verify(firstConverter).canRead(listOfIntegers.getType(), List.class, JSON); verify(firstConverter).canRead(listOfIntegers.getType(), List.class, JSON);
} }
@ -103,9 +104,9 @@ class HttpMessageContentConverterTests {
GenericHttpMessageConverter<?> firstConverter = mock(GenericHttpMessageConverter.class); GenericHttpMessageConverter<?> firstConverter = mock(GenericHttpMessageConverter.class);
SmartHttpMessageConverter<?> smartConverter = mockSmartConverterForRead( SmartHttpMessageConverter<?> smartConverter = mockSmartConverterForRead(
listOfIntegers, JSON, message, List.of(1, 2, 3)); listOfIntegers, JSON, message, List.of(1, 2, 3));
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of( DefaultJsonConverterDelegate converter =
List.of(firstConverter, smartConverter)); new DefaultJsonConverterDelegate(List.of(firstConverter, smartConverter));
List<Integer> data = contentConverter.convert(message, JSON, listOfIntegers); List<Integer> data = converter.read(message, JSON, listOfIntegers);
assertThat(data).containsExactly(1, 2, 3); assertThat(data).containsExactly(1, 2, 3);
verify(smartConverter).canRead(listOfIntegers, JSON); verify(smartConverter).canRead(listOfIntegers, JSON);
} }
@ -117,9 +118,9 @@ class HttpMessageContentConverterTests {
listOfIntegers, JSON, message, List.of(1, 2, 3)); listOfIntegers, JSON, message, List.of(1, 2, 3));
HttpMessageConverter<?> thirdConverter = mockSimpleConverterForRead( HttpMessageConverter<?> thirdConverter = mockSimpleConverterForRead(
List.class, MediaType.TEXT_PLAIN, message, List.of(1, 2, 3)); List.class, MediaType.TEXT_PLAIN, message, List.of(1, 2, 3));
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of( DefaultJsonConverterDelegate converter =
List.of(jacksonMessageConverter, secondConverter, thirdConverter)); new DefaultJsonConverterDelegate(List.of(jacksonMessageConverter, secondConverter, thirdConverter));
List<Integer> data = contentConverter.convert(message, MediaType.TEXT_PLAIN, listOfIntegers); List<Integer> data = converter.read(message, MediaType.TEXT_PLAIN, listOfIntegers);
assertThat(data).containsExactly(1, 2, 3); assertThat(data).containsExactly(1, 2, 3);
verify(secondConverter).canRead(listOfIntegers, MediaType.TEXT_PLAIN); verify(secondConverter).canRead(listOfIntegers, MediaType.TEXT_PLAIN);
verify(thirdConverter).canRead(List.class, MediaType.TEXT_PLAIN); verify(thirdConverter).canRead(List.class, MediaType.TEXT_PLAIN);
@ -132,10 +133,9 @@ class HttpMessageContentConverterTests {
listOfIntegers, MediaType.TEXT_PLAIN, message, List.of(1, 2, 3)); listOfIntegers, MediaType.TEXT_PLAIN, message, List.of(1, 2, 3));
SmartHttpMessageConverter<?> htmlConverter = mockSmartConverterForRead( SmartHttpMessageConverter<?> htmlConverter = mockSmartConverterForRead(
listOfIntegers, MediaType.TEXT_HTML, message, List.of(3, 2, 1)); listOfIntegers, MediaType.TEXT_HTML, message, List.of(3, 2, 1));
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of( DefaultJsonConverterDelegate converter = new DefaultJsonConverterDelegate(List.of(textConverter, htmlConverter));
List.of(textConverter, htmlConverter));
assertThatIllegalStateException() assertThatIllegalStateException()
.isThrownBy(() -> contentConverter.convert(message, JSON, listOfIntegers)) .isThrownBy(() -> converter.read(message, JSON, listOfIntegers))
.withMessage("No converter found to read [application/json] to [java.util.List<java.lang.Integer>]"); .withMessage("No converter found to read [application/json] to [java.util.List<java.lang.Integer>]");
verify(textConverter).canRead(listOfIntegers, JSON); verify(textConverter).canRead(listOfIntegers, JSON);
verify(htmlConverter).canRead(listOfIntegers, JSON); verify(htmlConverter).canRead(listOfIntegers, JSON);
@ -148,9 +148,9 @@ class HttpMessageContentConverterTests {
SmartHttpMessageConverter<?> readConverter = mockSmartConverterForRead(listOfIntegers, JSON, null, List.of(1, 2, 3)); SmartHttpMessageConverter<?> readConverter = mockSmartConverterForRead(listOfIntegers, JSON, null, List.of(1, 2, 3));
SmartHttpMessageConverter<?> firstWriteJsonConverter = mockSmartConverterForWritingJson(value, valueType, "[1,2,3]"); SmartHttpMessageConverter<?> firstWriteJsonConverter = mockSmartConverterForWritingJson(value, valueType, "[1,2,3]");
SmartHttpMessageConverter<?> secondWriteJsonConverter = mockSmartConverterForWritingJson(value, valueType, "[3,2,1]"); SmartHttpMessageConverter<?> secondWriteJsonConverter = mockSmartConverterForWritingJson(value, valueType, "[3,2,1]");
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of( JsonConverterDelegate converter =
List.of(readConverter, firstWriteJsonConverter, secondWriteJsonConverter)); new DefaultJsonConverterDelegate(List.of(readConverter, firstWriteJsonConverter, secondWriteJsonConverter));
List<Integer> data = contentConverter.convertViaJson(value, listOfIntegers); List<Integer> data = converter.map(value, listOfIntegers);
assertThat(data).containsExactly(1, 2, 3); assertThat(data).containsExactly(1, 2, 3);
verify(readConverter).canRead(listOfIntegers, JSON); verify(readConverter).canRead(listOfIntegers, JSON);
verify(firstWriteJsonConverter).canWrite(valueType, String.class, JSON); verify(firstWriteJsonConverter).canWrite(valueType, String.class, JSON);
@ -163,9 +163,9 @@ class HttpMessageContentConverterTests {
ResolvableType valueType = ResolvableType.forInstance(value); ResolvableType valueType = ResolvableType.forInstance(value);
SmartHttpMessageConverter<?> readConverter = mockSmartConverterForRead(listOfIntegers, JSON, null, List.of(1, 2, 3)); SmartHttpMessageConverter<?> readConverter = mockSmartConverterForRead(listOfIntegers, JSON, null, List.of(1, 2, 3));
GenericHttpMessageConverter<?> writeConverter = mockGenericConverterForWritingJson(value, valueType, "[3,2,1]"); GenericHttpMessageConverter<?> writeConverter = mockGenericConverterForWritingJson(value, valueType, "[3,2,1]");
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of( JsonConverterDelegate converter =
List.of(readConverter, writeConverter, jacksonMessageConverter)); new DefaultJsonConverterDelegate(List.of(readConverter, writeConverter, jacksonMessageConverter));
List<Integer> data = contentConverter.convertViaJson("[1, 2, 3]", listOfIntegers); List<Integer> data = converter.map("[1, 2, 3]", listOfIntegers);
assertThat(data).containsExactly(1, 2, 3); assertThat(data).containsExactly(1, 2, 3);
verify(readConverter).canRead(listOfIntegers, JSON); verify(readConverter).canRead(listOfIntegers, JSON);
verify(writeConverter).canWrite(valueType.getType(), value.getClass(), JSON); verify(writeConverter).canWrite(valueType.getType(), value.getClass(), JSON);
@ -177,9 +177,9 @@ class HttpMessageContentConverterTests {
ResolvableType valueType = ResolvableType.forInstance(value); ResolvableType valueType = ResolvableType.forInstance(value);
SmartHttpMessageConverter<?> readConverter = mockSmartConverterForRead(listOfIntegers, JSON, null, List.of(1, 2, 3)); SmartHttpMessageConverter<?> readConverter = mockSmartConverterForRead(listOfIntegers, JSON, null, List.of(1, 2, 3));
SmartHttpMessageConverter<?> writeConverter = mockSmartConverterForWritingJson(value, valueType, "[3,2,1]"); SmartHttpMessageConverter<?> writeConverter = mockSmartConverterForWritingJson(value, valueType, "[3,2,1]");
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of( JsonConverterDelegate converter =
List.of(readConverter, writeConverter, jacksonMessageConverter)); new DefaultJsonConverterDelegate(List.of(readConverter, writeConverter, jacksonMessageConverter));
List<Integer> data = contentConverter.convertViaJson("[1, 2, 3]", listOfIntegers); List<Integer> data = converter.map("[1, 2, 3]", listOfIntegers);
assertThat(data).containsExactly(1, 2, 3); assertThat(data).containsExactly(1, 2, 3);
verify(readConverter).canRead(listOfIntegers, JSON); verify(readConverter).canRead(listOfIntegers, JSON);
verify(writeConverter).canWrite(valueType, value.getClass(), JSON); verify(writeConverter).canWrite(valueType, value.getClass(), JSON);
@ -190,9 +190,9 @@ class HttpMessageContentConverterTests {
String value = "1,2,3"; String value = "1,2,3";
SmartHttpMessageConverter<?> readConverter = mockSmartConverterForRead(listOfIntegers, JSON, null, List.of(1, 2, 3)); SmartHttpMessageConverter<?> readConverter = mockSmartConverterForRead(listOfIntegers, JSON, null, List.of(1, 2, 3));
HttpMessageConverter<?> writeConverter = mockSimpleConverterForWritingJson(value, "[3,2,1]"); HttpMessageConverter<?> writeConverter = mockSimpleConverterForWritingJson(value, "[3,2,1]");
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of( JsonConverterDelegate converterDelegate =
List.of(readConverter, writeConverter, jacksonMessageConverter)); new DefaultJsonConverterDelegate(List.of(readConverter, writeConverter, jacksonMessageConverter));
List<Integer> data = contentConverter.convertViaJson("[1, 2, 3]", listOfIntegers); List<Integer> data = converterDelegate.map("[1, 2, 3]", listOfIntegers);
assertThat(data).containsExactly(1, 2, 3); assertThat(data).containsExactly(1, 2, 3);
verify(readConverter).canRead(listOfIntegers, JSON); verify(readConverter).canRead(listOfIntegers, JSON);
verify(writeConverter).canWrite(value.getClass(), JSON); verify(writeConverter).canWrite(value.getClass(), JSON);
@ -203,9 +203,9 @@ class HttpMessageContentConverterTests {
String value = "1,2,3"; String value = "1,2,3";
ResolvableType valueType = ResolvableType.forInstance(value); ResolvableType valueType = ResolvableType.forInstance(value);
SmartHttpMessageConverter<?> readConverter = mockSmartConverterForRead(listOfIntegers, JSON, null, List.of(1, 2, 3)); SmartHttpMessageConverter<?> readConverter = mockSmartConverterForRead(listOfIntegers, JSON, null, List.of(1, 2, 3));
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of(List.of(readConverter)); JsonConverterDelegate converter = new DefaultJsonConverterDelegate(List.of(readConverter));
assertThatIllegalStateException() assertThatIllegalStateException()
.isThrownBy(() -> contentConverter.convertViaJson(value, listOfIntegers)) .isThrownBy(() -> converter.map(value, listOfIntegers))
.withMessage("No converter found to convert [java.lang.String] to JSON"); .withMessage("No converter found to convert [java.lang.String] to JSON");
verify(readConverter).canWrite(valueType, value.getClass(), JSON); verify(readConverter).canWrite(valueType, value.getClass(), JSON);
} }

9
spring-test/src/test/java/org/springframework/test/json/JsonContentTests.java

@ -16,10 +16,11 @@
package org.springframework.test.json; package org.springframework.test.json;
import java.util.List;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.test.http.HttpMessageContentConverter;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
@ -63,9 +64,9 @@ class JsonContentTests {
@Test @Test
void getJsonContentConverterShouldReturnConverter() { void getJsonContentConverterShouldReturnConverter() {
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of(mock(HttpMessageConverter.class)); JsonConverterDelegate converter = JsonConverterDelegate.of(List.of(mock(HttpMessageConverter.class)));
JsonContent content = new JsonContent(JSON, contentConverter); JsonContent content = new JsonContent(JSON, converter);
assertThat(content.getContentConverter()).isSameAs(contentConverter); assertThat(content.getJsonConverterDelegate()).isSameAs(converter);
} }
} }

5
spring-test/src/test/java/org/springframework/test/json/JsonPathValueAssertTests.java

@ -30,7 +30,6 @@ import org.junit.jupiter.api.Test;
import tools.jackson.databind.json.JsonMapper; import tools.jackson.databind.json.JsonMapper;
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter; import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
import org.springframework.test.http.HttpMessageContentConverter;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -205,8 +204,8 @@ class JsonPathValueAssertTests {
@Nested @Nested
class ConvertToTests { class ConvertToTests {
private static final HttpMessageContentConverter jsonContentConverter = HttpMessageContentConverter.of( private static final JsonConverterDelegate jsonContentConverter =
new JacksonJsonHttpMessageConverter(new JsonMapper())); JsonConverterDelegate.of(List.of(new JacksonJsonHttpMessageConverter(new JsonMapper())));
@Test @Test
void convertToWithoutHttpMessageConverter() { void convertToWithoutHttpMessageConverter() {

3
spring-test/src/test/java/org/springframework/test/web/servlet/assertj/AbstractMockHttpServletResponseAssertTests.java

@ -25,6 +25,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.json.JsonContent; import org.springframework.test.json.JsonContent;
import org.springframework.test.json.JsonConverterDelegate;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -138,7 +139,7 @@ public class AbstractMockHttpServletResponseAssertTests {
private static final class ResponseAssert extends AbstractMockHttpServletResponseAssert<ResponseAssert, MockHttpServletResponse> { private static final class ResponseAssert extends AbstractMockHttpServletResponseAssert<ResponseAssert, MockHttpServletResponse> {
ResponseAssert(MockHttpServletResponse actual) { ResponseAssert(MockHttpServletResponse actual) {
super(null, actual, ResponseAssert.class); super((JsonConverterDelegate) null, actual, ResponseAssert.class);
} }
@Override @Override

Loading…
Cancel
Save