Introduce HttpMessageContentConverter
This commit introduces an abstraction that allows to convert HTTP inputs to a data type based on a set of HttpMessageConverter. Previously, the AssertJ integration was finding the first converter that is able to convert JSON to a Map (and vice-versa) and used that in its API. With the introduction of SmartHttpMessageConverter, exposing a specific converter is fragile. The added abstraction allows for converting other kind of input than JSON if we need to do that in the future. Closes gh-33148
This commit is contained in:
parent
206d81ee08
commit
4bdb772d39
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright 2002-2024 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.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Convert HTTP message content for testing purposes.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.2
|
||||
*/
|
||||
public class HttpMessageContentConverter {
|
||||
|
||||
private static final MediaType JSON = MediaType.APPLICATION_JSON;
|
||||
|
||||
private final List<HttpMessageConverter<?>> messageConverters;
|
||||
|
||||
HttpMessageContentConverter(Iterable<HttpMessageConverter<?>> messageConverters) {
|
||||
this.messageConverters = StreamSupport.stream(messageConverters.spliterator(), false).toList();
|
||||
Assert.notEmpty(this.messageConverters, "At least one message converter needs to be specified");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create an instance with an iterable of the candidates to use.
|
||||
* @param candidates the candidates
|
||||
*/
|
||||
public static HttpMessageContentConverter of(Iterable<HttpMessageConverter<?>> candidates) {
|
||||
return new HttpMessageContentConverter(candidates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance with a vararg of the candidates to use.
|
||||
* @param candidates the candidates
|
||||
*/
|
||||
public static HttpMessageContentConverter of(HttpMessageConverter<?>... candidates) {
|
||||
return new HttpMessageContentConverter(Arrays.asList(candidates));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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")
|
||||
public <T> T convert(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}
|
||||
*/
|
||||
public <T> T convertViaJson(Object value, ResolvableType targetType) throws IOException {
|
||||
MockHttpOutputMessage outputMessage = convertToJson(value, ResolvableType.forInstance(value));
|
||||
return convert(fromHttpOutputMessage(outputMessage), JSON, targetType);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private MockHttpOutputMessage convertToJson(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;
|
||||
}
|
||||
|
||||
}
|
|
@ -35,6 +35,7 @@ import org.assertj.core.api.InstanceOfAssertFactories;
|
|||
import org.assertj.core.error.BasicErrorMessageFactory;
|
||||
import org.assertj.core.internal.Failures;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
|
@ -43,9 +44,9 @@ import org.springframework.core.io.Resource;
|
|||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.mock.http.MockHttpInputMessage;
|
||||
import org.springframework.test.http.HttpMessageContentConverter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
@ -77,7 +78,7 @@ public abstract class AbstractJsonContentAssert<SELF extends AbstractJsonContent
|
|||
|
||||
|
||||
@Nullable
|
||||
private final GenericHttpMessageConverter<Object> jsonMessageConverter;
|
||||
private final HttpMessageContentConverter contentConverter;
|
||||
|
||||
@Nullable
|
||||
private Class<?> resourceLoadClass;
|
||||
|
@ -94,7 +95,7 @@ public abstract class AbstractJsonContentAssert<SELF extends AbstractJsonContent
|
|||
*/
|
||||
protected AbstractJsonContentAssert(@Nullable JsonContent actual, Class<?> selfType) {
|
||||
super(actual, selfType);
|
||||
this.jsonMessageConverter = (actual != null ? actual.getJsonMessageConverter() : null);
|
||||
this.contentConverter = (actual != null ? actual.getContentConverter() : null);
|
||||
this.jsonLoader = new JsonLoader(null, null);
|
||||
as("JSON content");
|
||||
}
|
||||
|
@ -131,15 +132,15 @@ public abstract class AbstractJsonContentAssert<SELF extends AbstractJsonContent
|
|||
return assertFactory.createAssert(this::convertToTargetType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T convertToTargetType(Type targetType) {
|
||||
String json = this.actual.getJson();
|
||||
if (this.jsonMessageConverter == null) {
|
||||
if (this.contentConverter == null) {
|
||||
throw new IllegalStateException(
|
||||
"No JSON message converter available to convert %s".formatted(json));
|
||||
}
|
||||
try {
|
||||
return (T) this.jsonMessageConverter.read(targetType, getClass(), fromJson(json));
|
||||
return this.contentConverter.convert(fromJson(json), MediaType.APPLICATION_JSON,
|
||||
ResolvableType.forType(targetType));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw failure(new ValueProcessingFailed(json,
|
||||
|
@ -165,7 +166,7 @@ public abstract class AbstractJsonContentAssert<SELF extends AbstractJsonContent
|
|||
*/
|
||||
public JsonPathValueAssert extractingPath(String path) {
|
||||
Object value = new JsonPathValue(path).getValue();
|
||||
return new JsonPathValueAssert(value, path, this.jsonMessageConverter);
|
||||
return new JsonPathValueAssert(value, path, this.contentConverter);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -176,7 +177,7 @@ public abstract class AbstractJsonContentAssert<SELF extends AbstractJsonContent
|
|||
*/
|
||||
public SELF hasPathSatisfying(String path, Consumer<AssertProvider<JsonPathValueAssert>> valueRequirements) {
|
||||
Object value = new JsonPathValue(path).assertHasPath();
|
||||
JsonPathValueAssert valueAssert = new JsonPathValueAssert(value, path, this.jsonMessageConverter);
|
||||
JsonPathValueAssert valueAssert = new JsonPathValueAssert(value, path, this.contentConverter);
|
||||
valueRequirements.accept(() -> valueAssert);
|
||||
return this.myself;
|
||||
}
|
||||
|
|
|
@ -33,12 +33,9 @@ import org.assertj.core.error.BasicErrorMessageFactory;
|
|||
import org.assertj.core.internal.Failures;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.mock.http.MockHttpInputMessage;
|
||||
import org.springframework.mock.http.MockHttpOutputMessage;
|
||||
import org.springframework.test.http.HttpMessageContentConverter;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
@ -68,14 +65,14 @@ public abstract class AbstractJsonValueAssert<SELF extends AbstractJsonValueAsse
|
|||
private final Failures failures = Failures.instance();
|
||||
|
||||
@Nullable
|
||||
private final GenericHttpMessageConverter<Object> httpMessageConverter;
|
||||
private final HttpMessageContentConverter contentConverter;
|
||||
|
||||
|
||||
protected AbstractJsonValueAssert(@Nullable Object actual, Class<?> selfType,
|
||||
@Nullable GenericHttpMessageConverter<Object> httpMessageConverter) {
|
||||
@Nullable HttpMessageContentConverter contentConverter) {
|
||||
|
||||
super(actual, selfType);
|
||||
this.httpMessageConverter = httpMessageConverter;
|
||||
this.contentConverter = contentConverter;
|
||||
}
|
||||
|
||||
|
||||
|
@ -199,19 +196,13 @@ public abstract class AbstractJsonValueAssert<SELF extends AbstractJsonValueAsse
|
|||
return this.myself;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T convertToTargetType(Type targetType) {
|
||||
if (this.httpMessageConverter == null) {
|
||||
if (this.contentConverter == null) {
|
||||
throw new IllegalStateException(
|
||||
"No JSON message converter available to convert %s".formatted(actualToString()));
|
||||
}
|
||||
try {
|
||||
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
|
||||
this.httpMessageConverter.write(this.actual, ResolvableType.forInstance(this.actual).getType(),
|
||||
MediaType.APPLICATION_JSON, outputMessage);
|
||||
return (T) this.httpMessageConverter.read(targetType, getClass(),
|
||||
fromHttpOutputMessage(outputMessage));
|
||||
return this.contentConverter.convertViaJson(this.actual, ResolvableType.forType(targetType));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw valueProcessingFailed("To convert successfully to:%n %s%nBut it failed:%n %s%n"
|
||||
|
@ -219,12 +210,6 @@ public abstract class AbstractJsonValueAssert<SELF extends AbstractJsonValueAsse
|
|||
}
|
||||
}
|
||||
|
||||
private HttpInputMessage fromHttpOutputMessage(MockHttpOutputMessage message) {
|
||||
MockHttpInputMessage inputMessage = new MockHttpInputMessage(message.getBodyAsBytes());
|
||||
inputMessage.getHeaders().addAll(message.getHeaders());
|
||||
return inputMessage;
|
||||
}
|
||||
|
||||
protected String getExpectedErrorMessagePrefix() {
|
||||
return "Expected:";
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@ package org.springframework.test.json;
|
|||
|
||||
import org.assertj.core.api.AssertProvider;
|
||||
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.http.HttpMessageContentConverter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
@ -35,22 +35,21 @@ public final class JsonContent implements AssertProvider<JsonContentAssert> {
|
|||
private final String json;
|
||||
|
||||
@Nullable
|
||||
private final GenericHttpMessageConverter<Object> jsonMessageConverter;
|
||||
private final HttpMessageContentConverter contentConverter;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code JsonContent} instance with the message converter to
|
||||
* use to deserialize content.
|
||||
* @param json the actual JSON content
|
||||
* @param jsonMessageConverter the message converter to use
|
||||
* @param contentConverter the content converter to use
|
||||
*/
|
||||
public JsonContent(String json, @Nullable GenericHttpMessageConverter<Object> jsonMessageConverter) {
|
||||
public JsonContent(String json, @Nullable HttpMessageContentConverter contentConverter) {
|
||||
Assert.notNull(json, "JSON must not be null");
|
||||
this.json = json;
|
||||
this.jsonMessageConverter = jsonMessageConverter;
|
||||
this.contentConverter = contentConverter;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code JsonContent} instance.
|
||||
* @param json the actual JSON content
|
||||
|
@ -59,6 +58,7 @@ public final class JsonContent implements AssertProvider<JsonContentAssert> {
|
|||
this(json, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Use AssertJ's {@link org.assertj.core.api.Assertions#assertThat assertThat}
|
||||
* instead.
|
||||
|
@ -76,11 +76,11 @@ public final class JsonContent implements AssertProvider<JsonContentAssert> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return the message converter to use to deserialize content.
|
||||
* Return the {@link HttpMessageContentConverter} to use to deserialize content.
|
||||
*/
|
||||
@Nullable
|
||||
GenericHttpMessageConverter<Object> getJsonMessageConverter() {
|
||||
return this.jsonMessageConverter;
|
||||
HttpMessageContentConverter getContentConverter() {
|
||||
return this.contentConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,8 +18,8 @@ package org.springframework.test.json;
|
|||
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.http.HttpMessageContentConverter;
|
||||
|
||||
/**
|
||||
* AssertJ {@linkplain org.assertj.core.api.Assert assertions} that can be applied
|
||||
|
@ -35,9 +35,9 @@ public class JsonPathValueAssert extends AbstractJsonValueAssert<JsonPathValueAs
|
|||
|
||||
|
||||
JsonPathValueAssert(@Nullable Object actual, String expression,
|
||||
@Nullable GenericHttpMessageConverter<Object> httpMessageConverter) {
|
||||
@Nullable HttpMessageContentConverter contentConverter) {
|
||||
|
||||
super(actual, JsonPathValueAssert.class, httpMessageConverter);
|
||||
super(actual, JsonPathValueAssert.class, contentConverter);
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,9 +23,9 @@ import org.assertj.core.api.AbstractStringAssert;
|
|||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.api.ByteArrayAssert;
|
||||
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.test.http.HttpMessageContentConverter;
|
||||
import org.springframework.test.json.AbstractJsonContentAssert;
|
||||
import org.springframework.test.json.JsonContent;
|
||||
import org.springframework.test.json.JsonContentAssert;
|
||||
|
@ -44,13 +44,13 @@ public abstract class AbstractMockHttpServletResponseAssert<SELF extends Abstrac
|
|||
extends AbstractHttpServletResponseAssert<MockHttpServletResponse, SELF, ACTUAL> {
|
||||
|
||||
@Nullable
|
||||
private final GenericHttpMessageConverter<Object> jsonMessageConverter;
|
||||
private final HttpMessageContentConverter contentConverter;
|
||||
|
||||
protected AbstractMockHttpServletResponseAssert(
|
||||
@Nullable GenericHttpMessageConverter<Object> jsonMessageConverter, ACTUAL actual, Class<?> selfType) {
|
||||
@Nullable HttpMessageContentConverter contentConverter, ACTUAL actual, Class<?> selfType) {
|
||||
|
||||
super(actual, selfType);
|
||||
this.jsonMessageConverter = jsonMessageConverter;
|
||||
this.contentConverter = contentConverter;
|
||||
}
|
||||
|
||||
|
||||
|
@ -93,7 +93,7 @@ public abstract class AbstractMockHttpServletResponseAssert<SELF extends Abstrac
|
|||
* </code></pre>
|
||||
*/
|
||||
public AbstractJsonContentAssert<?> bodyJson() {
|
||||
return new JsonContentAssert(new JsonContent(readBody(), this.jsonMessageConverter));
|
||||
return new JsonContentAssert(new JsonContent(readBody(), this.contentConverter));
|
||||
}
|
||||
|
||||
private String readBody() {
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
package org.springframework.test.web.servlet.assertj;
|
||||
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.http.HttpMessageContentConverter;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
/**
|
||||
|
@ -35,15 +35,15 @@ final class DefaultMvcTestResult implements MvcTestResult {
|
|||
private final Exception unresolvedException;
|
||||
|
||||
@Nullable
|
||||
private final GenericHttpMessageConverter<Object> jsonMessageConverter;
|
||||
private final HttpMessageContentConverter contentConverter;
|
||||
|
||||
|
||||
DefaultMvcTestResult(@Nullable MvcResult mvcResult, @Nullable Exception unresolvedException,
|
||||
@Nullable GenericHttpMessageConverter<Object> jsonMessageConverter) {
|
||||
@Nullable HttpMessageContentConverter contentConverter) {
|
||||
|
||||
this.mvcResult = mvcResult;
|
||||
this.unresolvedException = unresolvedException;
|
||||
this.jsonMessageConverter = jsonMessageConverter;
|
||||
this.contentConverter = contentConverter;
|
||||
}
|
||||
|
||||
|
||||
|
@ -74,7 +74,7 @@ final class DefaultMvcTestResult implements MvcTestResult {
|
|||
*/
|
||||
@Override
|
||||
public MvcTestResultAssert assertThat() {
|
||||
return new MvcTestResultAssert(this, this.jsonMessageConverter);
|
||||
return new MvcTestResultAssert(this, this.contentConverter);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,20 +20,17 @@ import java.net.URI;
|
|||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import jakarta.servlet.DispatcherType;
|
||||
import org.assertj.core.api.AssertProvider;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockMultipartHttpServletRequest;
|
||||
import org.springframework.test.http.HttpMessageContentConverter;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.RequestBuilder;
|
||||
|
@ -133,18 +130,16 @@ import org.springframework.web.context.WebApplicationContext;
|
|||
*/
|
||||
public final class MockMvcTester {
|
||||
|
||||
private static final MediaType JSON = MediaType.APPLICATION_JSON;
|
||||
|
||||
private final MockMvc mockMvc;
|
||||
|
||||
@Nullable
|
||||
private final GenericHttpMessageConverter<Object> jsonMessageConverter;
|
||||
private final HttpMessageContentConverter contentConverter;
|
||||
|
||||
|
||||
private MockMvcTester(MockMvc mockMvc, @Nullable GenericHttpMessageConverter<Object> jsonMessageConverter) {
|
||||
private MockMvcTester(MockMvc mockMvc, @Nullable HttpMessageContentConverter contentConverter) {
|
||||
Assert.notNull(mockMvc, "mockMVC should not be null");
|
||||
this.mockMvc = mockMvc;
|
||||
this.jsonMessageConverter = jsonMessageConverter;
|
||||
this.contentConverter = contentConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -238,7 +233,7 @@ public final class MockMvcTester {
|
|||
* @return a new instance using the specified converters
|
||||
*/
|
||||
public MockMvcTester withHttpMessageConverters(Iterable<HttpMessageConverter<?>> httpMessageConverters) {
|
||||
return new MockMvcTester(this.mockMvc, findJsonMessageConverter(httpMessageConverters));
|
||||
return new MockMvcTester(this.mockMvc, HttpMessageContentConverter.of(httpMessageConverters));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -380,10 +375,10 @@ public final class MockMvcTester {
|
|||
public MvcTestResult perform(RequestBuilder requestBuilder) {
|
||||
Object result = getMvcResultOrFailure(requestBuilder);
|
||||
if (result instanceof MvcResult mvcResult) {
|
||||
return new DefaultMvcTestResult(mvcResult, null, this.jsonMessageConverter);
|
||||
return new DefaultMvcTestResult(mvcResult, null, this.contentConverter);
|
||||
}
|
||||
else {
|
||||
return new DefaultMvcTestResult(null, (Exception) result, this.jsonMessageConverter);
|
||||
return new DefaultMvcTestResult(null, (Exception) result, this.contentConverter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -396,19 +391,6 @@ public final class MockMvcTester {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
private GenericHttpMessageConverter<Object> findJsonMessageConverter(
|
||||
Iterable<HttpMessageConverter<?>> messageConverters) {
|
||||
|
||||
return StreamSupport.stream(messageConverters.spliterator(), false)
|
||||
.filter(GenericHttpMessageConverter.class::isInstance)
|
||||
.map(GenericHttpMessageConverter.class::cast)
|
||||
.filter(converter -> converter.canWrite(null, Map.class, JSON))
|
||||
.filter(converter -> converter.canRead(Map.class, JSON))
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the request using the specified {@link RequestBuilder}. If the
|
||||
* request is processing asynchronously, wait at most the given
|
||||
|
@ -502,7 +484,7 @@ public final class MockMvcTester {
|
|||
|
||||
@Override
|
||||
public MvcTestResultAssert assertThat() {
|
||||
return new MvcTestResultAssert(exchange(), MockMvcTester.this.jsonMessageConverter);
|
||||
return new MvcTestResultAssert(exchange(), MockMvcTester.this.contentConverter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -560,7 +542,7 @@ public final class MockMvcTester {
|
|||
|
||||
@Override
|
||||
public MvcTestResultAssert assertThat() {
|
||||
return new MvcTestResultAssert(exchange(), MockMvcTester.this.jsonMessageConverter);
|
||||
return new MvcTestResultAssert(exchange(), MockMvcTester.this.contentConverter);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,10 +31,10 @@ import org.assertj.core.api.MapAssert;
|
|||
import org.assertj.core.error.BasicErrorMessageFactory;
|
||||
import org.assertj.core.internal.Failures;
|
||||
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.test.http.HttpMessageContentConverter;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.ResultHandler;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
|
@ -51,8 +51,8 @@ import org.springframework.web.servlet.ModelAndView;
|
|||
*/
|
||||
public class MvcTestResultAssert extends AbstractMockHttpServletResponseAssert<MvcTestResultAssert, MvcTestResult> {
|
||||
|
||||
MvcTestResultAssert(MvcTestResult actual, @Nullable GenericHttpMessageConverter<Object> jsonMessageConverter) {
|
||||
super(jsonMessageConverter, actual, MvcTestResultAssert.class);
|
||||
MvcTestResultAssert(MvcTestResult actual, @Nullable HttpMessageContentConverter contentConverter) {
|
||||
super(contentConverter, actual, MvcTestResultAssert.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* Copyright 2002-2024 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.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
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.SmartHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.mock.http.MockHttpInputMessage;
|
||||
import org.springframework.mock.http.MockHttpOutputMessage;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.willAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
|
||||
/**
|
||||
* Tests for {@link HttpMessageContentConverter}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class HttpMessageContentConverterTests {
|
||||
|
||||
private static final MediaType JSON = MediaType.APPLICATION_JSON;
|
||||
|
||||
private static final ResolvableType listOfIntegers = ResolvableType.forClassWithGenerics(List.class, Integer.class);
|
||||
|
||||
private static final MappingJackson2HttpMessageConverter jacksonMessageConverter =
|
||||
new MappingJackson2HttpMessageConverter(new ObjectMapper());
|
||||
|
||||
@Test
|
||||
void createInstanceWithEmptyIterable() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> HttpMessageContentConverter.of(List.of()))
|
||||
.withMessage("At least one message converter needs to be specified");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createInstanceWithEmptyVarArg() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(HttpMessageContentConverter::of)
|
||||
.withMessage("At least one message converter needs to be specified");
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertInvokesFirstMatchingConverter() throws IOException {
|
||||
HttpInputMessage message = createMessage("1,2,3");
|
||||
SmartHttpMessageConverter<?> firstConverter = mockSmartConverterForRead(
|
||||
listOfIntegers, JSON, message, List.of(1, 2, 3));
|
||||
SmartHttpMessageConverter<?> secondConverter = mockSmartConverterForRead(
|
||||
listOfIntegers, JSON, message, List.of(3, 2, 1));
|
||||
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of(
|
||||
List.of(firstConverter, secondConverter));
|
||||
List<Integer> data = contentConverter.convert(message, JSON, listOfIntegers);
|
||||
assertThat(data).containsExactly(1, 2, 3);
|
||||
verify(firstConverter).canRead(listOfIntegers, JSON);
|
||||
verifyNoInteractions(secondConverter);
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertInvokesGenericHttpMessageConverter() throws IOException {
|
||||
GenericHttpMessageConverter<?> firstConverter = mock(GenericHttpMessageConverter.class);
|
||||
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of(
|
||||
List.of(firstConverter, jacksonMessageConverter));
|
||||
List<Integer> data = contentConverter.convert(createMessage("[2,3,4]"), JSON, listOfIntegers);
|
||||
assertThat(data).containsExactly(2, 3, 4);
|
||||
verify(firstConverter).canRead(listOfIntegers.getType(), List.class, JSON);
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertInvokesSmartHttpMessageConverter() throws IOException {
|
||||
HttpInputMessage message = createMessage("dummy");
|
||||
GenericHttpMessageConverter<?> firstConverter = mock(GenericHttpMessageConverter.class);
|
||||
SmartHttpMessageConverter<?> smartConverter = mockSmartConverterForRead(
|
||||
listOfIntegers, JSON, message, List.of(1, 2, 3));
|
||||
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of(
|
||||
List.of(firstConverter, smartConverter));
|
||||
List<Integer> data = contentConverter.convert(message, JSON, listOfIntegers);
|
||||
assertThat(data).containsExactly(1, 2, 3);
|
||||
verify(smartConverter).canRead(listOfIntegers, JSON);
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertInvokesHttpMessageConverter() throws IOException {
|
||||
HttpInputMessage message = createMessage("1,2,3");
|
||||
SmartHttpMessageConverter<?> secondConverter = mockSmartConverterForRead(
|
||||
listOfIntegers, JSON, message, List.of(1, 2, 3));
|
||||
HttpMessageConverter<?> thirdConverter = mockSimpleConverterForRead(
|
||||
List.class, MediaType.TEXT_PLAIN, message, List.of(1, 2, 3));
|
||||
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of(
|
||||
List.of(jacksonMessageConverter, secondConverter, thirdConverter));
|
||||
List<Integer> data = contentConverter.convert(message, MediaType.TEXT_PLAIN, listOfIntegers);
|
||||
assertThat(data).containsExactly(1, 2, 3);
|
||||
verify(secondConverter).canRead(listOfIntegers, MediaType.TEXT_PLAIN);
|
||||
verify(thirdConverter).canRead(List.class, MediaType.TEXT_PLAIN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertFailsIfNoMatchingConverterIsFound() throws IOException {
|
||||
HttpInputMessage message = createMessage("[1,2,3]");
|
||||
SmartHttpMessageConverter<?> textConverter = mockSmartConverterForRead(
|
||||
listOfIntegers, MediaType.TEXT_PLAIN, message, List.of(1, 2, 3));
|
||||
SmartHttpMessageConverter<?> htmlConverter = mockSmartConverterForRead(
|
||||
listOfIntegers, MediaType.TEXT_HTML, message, List.of(3, 2, 1));
|
||||
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of(
|
||||
List.of(textConverter, htmlConverter));
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> contentConverter.convert(message, JSON, listOfIntegers))
|
||||
.withMessage("No converter found to read [application/json] to [java.util.List<java.lang.Integer>]");
|
||||
verify(textConverter).canRead(listOfIntegers, JSON);
|
||||
verify(htmlConverter).canRead(listOfIntegers, JSON);
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertViaJsonInvokesFirstMatchingConverter() throws IOException {
|
||||
String value = "1,2,3";
|
||||
ResolvableType valueType = ResolvableType.forInstance(value);
|
||||
SmartHttpMessageConverter<?> readConverter = mockSmartConverterForRead(listOfIntegers, JSON, null, List.of(1, 2, 3));
|
||||
SmartHttpMessageConverter<?> firstWriteJsonConverter = mockSmartConverterForWritingJson(value, valueType, "[1,2,3]");
|
||||
SmartHttpMessageConverter<?> secondWriteJsonConverter = mockSmartConverterForWritingJson(value, valueType, "[3,2,1]");
|
||||
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of(
|
||||
List.of(readConverter, firstWriteJsonConverter, secondWriteJsonConverter));
|
||||
List<Integer> data = contentConverter.convertViaJson(value, listOfIntegers);
|
||||
assertThat(data).containsExactly(1, 2, 3);
|
||||
verify(readConverter).canRead(listOfIntegers, JSON);
|
||||
verify(firstWriteJsonConverter).canWrite(valueType, String.class, JSON);
|
||||
verifyNoInteractions(secondWriteJsonConverter);
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertViaJsonInvokesGenericHttpMessageConverter() throws IOException {
|
||||
String value = "1,2,3";
|
||||
ResolvableType valueType = ResolvableType.forInstance(value);
|
||||
SmartHttpMessageConverter<?> readConverter = mockSmartConverterForRead(listOfIntegers, JSON, null, List.of(1, 2, 3));
|
||||
GenericHttpMessageConverter<?> writeConverter = mockGenericConverterForWritingJson(value, valueType, "[3,2,1]");
|
||||
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of(
|
||||
List.of(readConverter, writeConverter, jacksonMessageConverter));
|
||||
List<Integer> data = contentConverter.convertViaJson("[1, 2, 3]", listOfIntegers);
|
||||
assertThat(data).containsExactly(1, 2, 3);
|
||||
verify(readConverter).canRead(listOfIntegers, JSON);
|
||||
verify(writeConverter).canWrite(valueType.getType(), value.getClass(), JSON);
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertViaJsonInvokesSmartHttpMessageConverter() throws IOException {
|
||||
String value = "1,2,3";
|
||||
ResolvableType valueType = ResolvableType.forInstance(value);
|
||||
SmartHttpMessageConverter<?> readConverter = mockSmartConverterForRead(listOfIntegers, JSON, null, List.of(1, 2, 3));
|
||||
SmartHttpMessageConverter<?> writeConverter = mockSmartConverterForWritingJson(value, valueType, "[3,2,1]");
|
||||
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of(
|
||||
List.of(readConverter, writeConverter, jacksonMessageConverter));
|
||||
List<Integer> data = contentConverter.convertViaJson("[1, 2, 3]", listOfIntegers);
|
||||
assertThat(data).containsExactly(1, 2, 3);
|
||||
verify(readConverter).canRead(listOfIntegers, JSON);
|
||||
verify(writeConverter).canWrite(valueType, value.getClass(), JSON);
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertViaJsonInvokesHttpMessageConverter() throws IOException {
|
||||
String value = "1,2,3";
|
||||
SmartHttpMessageConverter<?> readConverter = mockSmartConverterForRead(listOfIntegers, JSON, null, List.of(1, 2, 3));
|
||||
HttpMessageConverter<?> writeConverter = mockSimpleConverterForWritingJson(value, "[3,2,1]");
|
||||
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of(
|
||||
List.of(readConverter, writeConverter, jacksonMessageConverter));
|
||||
List<Integer> data = contentConverter.convertViaJson("[1, 2, 3]", listOfIntegers);
|
||||
assertThat(data).containsExactly(1, 2, 3);
|
||||
verify(readConverter).canRead(listOfIntegers, JSON);
|
||||
verify(writeConverter).canWrite(value.getClass(), JSON);
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertViaJsonFailsIfNoMatchingConverterIsFound() throws IOException {
|
||||
String value = "1,2,3";
|
||||
ResolvableType valueType = ResolvableType.forInstance(value);
|
||||
SmartHttpMessageConverter<?> readConverter = mockSmartConverterForRead(listOfIntegers, JSON, null, List.of(1, 2, 3));
|
||||
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of(List.of(readConverter));
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> contentConverter.convertViaJson(value, listOfIntegers))
|
||||
.withMessage("No converter found to convert [java.lang.String] to JSON");
|
||||
verify(readConverter).canWrite(valueType, value.getClass(), JSON);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static SmartHttpMessageConverter<?> mockSmartConverterForRead(
|
||||
ResolvableType type, MediaType mediaType, @Nullable HttpInputMessage message, Object value) throws IOException {
|
||||
SmartHttpMessageConverter<Object> converter = mock(SmartHttpMessageConverter.class);
|
||||
given(converter.canRead(type, mediaType)).willReturn(true);
|
||||
given(converter.read(eq(type), (message != null ? eq(message) : any()), any())).willReturn(value);
|
||||
return converter;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static SmartHttpMessageConverter<?> mockSmartConverterForWritingJson(Object value, ResolvableType valueType, String json) throws IOException {
|
||||
SmartHttpMessageConverter<Object> converter = mock(SmartHttpMessageConverter.class);
|
||||
given(converter.canWrite(valueType, value.getClass(), JSON)).willReturn(true);
|
||||
willAnswer(invocation -> {
|
||||
MockHttpOutputMessage out = invocation.getArgument(3, MockHttpOutputMessage.class);
|
||||
StreamUtils.copy(json, StandardCharsets.UTF_8, out.getBody());
|
||||
return null;
|
||||
}).given(converter).write(eq(value), eq(valueType), eq(JSON), any(), any());
|
||||
return converter;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static GenericHttpMessageConverter<?> mockGenericConverterForWritingJson(Object value, ResolvableType valueType, String json) throws IOException {
|
||||
GenericHttpMessageConverter<Object> converter = mock(GenericHttpMessageConverter.class);
|
||||
given(converter.canWrite(valueType.getType(), value.getClass(), JSON)).willReturn(true);
|
||||
willAnswer(invocation -> {
|
||||
MockHttpOutputMessage out = invocation.getArgument(4, MockHttpOutputMessage.class);
|
||||
StreamUtils.copy(json, StandardCharsets.UTF_8, out.getBody());
|
||||
return null;
|
||||
}).given(converter).write(eq(value), eq(valueType.getType()), eq(JSON), any());
|
||||
return converter;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static HttpMessageConverter<?> mockSimpleConverterForRead(
|
||||
Class<?> rawType, MediaType mediaType, HttpInputMessage message, Object value) throws IOException {
|
||||
HttpMessageConverter<Object> converter = mock(HttpMessageConverter.class);
|
||||
given(converter.canRead(rawType, mediaType)).willReturn(true);
|
||||
given(converter.read(rawType, message)).willReturn(value);
|
||||
return converter;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static HttpMessageConverter<?> mockSimpleConverterForWritingJson(Object value, String json) throws IOException {
|
||||
HttpMessageConverter<Object> converter = mock(HttpMessageConverter.class);
|
||||
given(converter.canWrite(value.getClass(), JSON)).willReturn(true);
|
||||
willAnswer(invocation -> {
|
||||
MockHttpOutputMessage out = invocation.getArgument(2, MockHttpOutputMessage.class);
|
||||
StreamUtils.copy(json, StandardCharsets.UTF_8, out.getBody());
|
||||
return null;
|
||||
}).given(converter).write(eq(value), eq(JSON), any());
|
||||
return converter;
|
||||
}
|
||||
|
||||
private static HttpInputMessage createMessage(String content) {
|
||||
return new MockHttpInputMessage(content.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
}
|
|
@ -51,9 +51,9 @@ import org.springframework.core.io.ClassPathResource;
|
|||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.http.HttpMessageContentConverter;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
@ -85,8 +85,8 @@ class AbstractJsonContentAssertTests {
|
|||
|
||||
private static final String DIFFERENT = loadJson("different.json");
|
||||
|
||||
private static final MappingJackson2HttpMessageConverter jsonHttpMessageConverter =
|
||||
new MappingJackson2HttpMessageConverter(new ObjectMapper());
|
||||
private static final HttpMessageContentConverter jsonContentConverter = HttpMessageContentConverter.of(
|
||||
new MappingJackson2HttpMessageConverter(new ObjectMapper()));
|
||||
|
||||
private static final JsonComparator comparator = JsonAssert.comparator(JsonCompareMode.LENIENT);
|
||||
|
||||
|
@ -108,14 +108,14 @@ class AbstractJsonContentAssertTests {
|
|||
|
||||
@Test
|
||||
void convertToTargetType() {
|
||||
assertThat(forJson(SIMPSONS, jsonHttpMessageConverter))
|
||||
assertThat(forJson(SIMPSONS, jsonContentConverter))
|
||||
.convertTo(Family.class)
|
||||
.satisfies(family -> assertThat(family.familyMembers()).hasSize(5));
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertToIncompatibleTargetTypeShouldFail() {
|
||||
AbstractJsonContentAssert<?> jsonAssert = assertThat(forJson(SIMPSONS, jsonHttpMessageConverter));
|
||||
AbstractJsonContentAssert<?> jsonAssert = assertThat(forJson(SIMPSONS, jsonContentConverter));
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> jsonAssert.convertTo(Member.class))
|
||||
.withMessageContainingAll("To convert successfully to:",
|
||||
|
@ -124,15 +124,15 @@ class AbstractJsonContentAssertTests {
|
|||
|
||||
@Test
|
||||
void convertUsingAssertFactory() {
|
||||
assertThat(forJson(SIMPSONS, jsonHttpMessageConverter))
|
||||
assertThat(forJson(SIMPSONS, jsonContentConverter))
|
||||
.convertTo(new FamilyAssertFactory())
|
||||
.hasFamilyMember("Homer");
|
||||
}
|
||||
|
||||
private AssertProvider<AbstractJsonContentAssert<?>> forJson(@Nullable String json,
|
||||
@Nullable GenericHttpMessageConverter<Object> jsonHttpMessageConverter) {
|
||||
@Nullable HttpMessageContentConverter jsonContentConverter) {
|
||||
|
||||
return () -> new TestJsonContentAssert(json, jsonHttpMessageConverter);
|
||||
return () -> new TestJsonContentAssert(json, jsonContentConverter);
|
||||
}
|
||||
|
||||
private static class FamilyAssertFactory extends InstanceOfAssertFactory<Family, FamilyAssert> {
|
||||
|
@ -320,14 +320,14 @@ class AbstractJsonContentAssertTests {
|
|||
|
||||
@Test
|
||||
void convertToTargetType() {
|
||||
assertThat(forJson(SIMPSONS, jsonHttpMessageConverter))
|
||||
assertThat(forJson(SIMPSONS, jsonContentConverter))
|
||||
.extractingPath("$.familyMembers[0]").convertTo(Member.class)
|
||||
.satisfies(member -> assertThat(member.name).isEqualTo("Homer"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertToIncompatibleTargetTypeShouldFail() {
|
||||
JsonPathValueAssert path = assertThat(forJson(SIMPSONS, jsonHttpMessageConverter))
|
||||
JsonPathValueAssert path = assertThat(forJson(SIMPSONS, jsonContentConverter))
|
||||
.extractingPath("$.familyMembers[0]");
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> path.convertTo(ExtractingPathTests.Customer.class))
|
||||
|
@ -337,7 +337,7 @@ class AbstractJsonContentAssertTests {
|
|||
|
||||
@Test
|
||||
void convertArrayUsingAssertFactory() {
|
||||
assertThat(forJson(SIMPSONS, jsonHttpMessageConverter))
|
||||
assertThat(forJson(SIMPSONS, jsonContentConverter))
|
||||
.extractingPath("$.familyMembers")
|
||||
.convertTo(InstanceOfAssertFactories.list(Member.class))
|
||||
.hasSize(5).element(0).isEqualTo(new Member("Homer"));
|
||||
|
@ -395,8 +395,8 @@ class AbstractJsonContentAssertTests {
|
|||
return () -> new TestJsonContentAssert(json, null);
|
||||
}
|
||||
|
||||
private AssertProvider<AbstractJsonContentAssert<?>> forJson(@Nullable String json, GenericHttpMessageConverter<Object> jsonHttpMessageConverter) {
|
||||
return () -> new TestJsonContentAssert(json, jsonHttpMessageConverter);
|
||||
private AssertProvider<AbstractJsonContentAssert<?>> forJson(@Nullable String json, HttpMessageContentConverter jsonContentConverter) {
|
||||
return () -> new TestJsonContentAssert(json, jsonContentConverter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -895,8 +895,8 @@ class AbstractJsonContentAssertTests {
|
|||
|
||||
private static class TestJsonContentAssert extends AbstractJsonContentAssert<TestJsonContentAssert> {
|
||||
|
||||
public TestJsonContentAssert(@Nullable String json, @Nullable GenericHttpMessageConverter<Object> jsonMessageConverter) {
|
||||
super((json != null ? new JsonContent(json, jsonMessageConverter) : null), TestJsonContentAssert.class);
|
||||
public TestJsonContentAssert(@Nullable String json, @Nullable HttpMessageContentConverter jsonContentConverter) {
|
||||
super((json != null ? new JsonContent(json, jsonContentConverter) : null), TestJsonContentAssert.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,8 @@ package org.springframework.test.json;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
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.assertThatIllegalArgumentException;
|
||||
|
@ -61,10 +62,10 @@ class JsonContentTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void getJsonMessageConverterShouldReturnConverter() {
|
||||
MappingJackson2HttpMessageConverter converter = mock(MappingJackson2HttpMessageConverter.class);
|
||||
JsonContent content = new JsonContent(JSON, converter);
|
||||
assertThat(content.getJsonMessageConverter()).isSameAs(converter);
|
||||
void getJsonContentConverterShouldReturnConverter() {
|
||||
HttpMessageContentConverter contentConverter = HttpMessageContentConverter.of(mock(HttpMessageConverter.class));
|
||||
JsonContent content = new JsonContent(JSON, contentConverter);
|
||||
assertThat(content.getContentConverter()).isSameAs(contentConverter);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.junit.jupiter.api.Test;
|
|||
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.http.HttpMessageContentConverter;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
@ -204,8 +205,8 @@ class JsonPathValueAssertTests {
|
|||
@Nested
|
||||
class ConvertToTests {
|
||||
|
||||
private static final MappingJackson2HttpMessageConverter jsonHttpMessageConverter =
|
||||
new MappingJackson2HttpMessageConverter(new ObjectMapper());
|
||||
private static final HttpMessageContentConverter jsonContentConverter = HttpMessageContentConverter.of(
|
||||
new MappingJackson2HttpMessageConverter(new ObjectMapper()));
|
||||
|
||||
@Test
|
||||
void convertToWithoutHttpMessageConverter() {
|
||||
|
@ -246,7 +247,7 @@ class JsonPathValueAssertTests {
|
|||
|
||||
|
||||
private AssertProvider<JsonPathValueAssert> forValue(@Nullable Object actual) {
|
||||
return () -> new JsonPathValueAssert(actual, "$.test", jsonHttpMessageConverter);
|
||||
return () -> new JsonPathValueAssert(actual, "$.test", jsonContentConverter);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
package org.springframework.test.web.servlet.assertj;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
@ -125,8 +125,7 @@ class MockMvcTesterTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void withHttpMessageConverterDetectsJsonConverter() {
|
||||
void withHttpMessageConverterUsesConverter() {
|
||||
MappingJackson2HttpMessageConverter converter = spy(jsonHttpMessageConverter);
|
||||
MockMvcTester mockMvc = MockMvcTester.of(HelloController.class)
|
||||
.withHttpMessageConverters(List.of(mock(), mock(), converter));
|
||||
|
@ -135,7 +134,7 @@ class MockMvcTesterTests {
|
|||
assertThat(message.message()).isEqualTo("Hello World");
|
||||
assertThat(message.counter()).isEqualTo(42);
|
||||
});
|
||||
verify(converter).canWrite(Map.class, MediaType.APPLICATION_JSON);
|
||||
verify(converter).canWrite(LinkedHashMap.class, LinkedHashMap.class, MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue