org.springframework.test.http.HttpMessageContentConverter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spring-test Show documentation
Show all versions of spring-test Show documentation
Spring TestContext Framework
/*
* 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> messageConverters;
HttpMessageContentConverter(Iterable> 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> 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 the converted object type
* @return a value of the given {@code targetType}
*/
@SuppressWarnings("unchecked")
public T convert(HttpInputMessage message, MediaType mediaType, ResolvableType targetType)
throws IOException, HttpMessageNotReadableException {
Class> contextClass = targetType.getRawClass();
SingletonSupplier 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 simpleMessageConverter = (HttpMessageConverter) 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 the converted object type
* @return a value of the given {@code targetType}
*/
public 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 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
© 2015 - 2025 Weber Informatics LLC | Privacy Policy