mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Use JsonMapper instead of ObjectMapper when relevant
This commit updates Jackson 3 JSON support to use JsonMapper instead of ObjectMapper in converters, codecs and view constructors. As a consequence, AbstractJacksonDecoder, AbstractJacksonEncoder, AbstractJacksonHttpMessageConverter and JacksonCodecSupport are now parameterized with <T extends ObjectMapper>. Closes gh-35282
This commit is contained in:
@@ -57,8 +57,9 @@ import org.springframework.util.MimeType;
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 7.0
|
||||
* @param <T> the type of {@link ObjectMapper}
|
||||
*/
|
||||
public abstract class AbstractJacksonDecoder extends JacksonCodecSupport implements HttpMessageDecoder<Object> {
|
||||
public abstract class AbstractJacksonDecoder<T extends ObjectMapper> extends JacksonCodecSupport<T> implements HttpMessageDecoder<Object> {
|
||||
|
||||
private int maxInMemorySize = 256 * 1024;
|
||||
|
||||
@@ -68,14 +69,14 @@ public abstract class AbstractJacksonDecoder extends JacksonCodecSupport impleme
|
||||
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
||||
* by {@link MapperBuilder#findModules(ClassLoader)} and {@link MimeType}s.
|
||||
*/
|
||||
protected AbstractJacksonDecoder(MapperBuilder<?, ?> builder, MimeType... mimeTypes) {
|
||||
protected AbstractJacksonDecoder(MapperBuilder<T, ?> builder, MimeType... mimeTypes) {
|
||||
super(builder, mimeTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new instance with the provided {@link ObjectMapper} and {@link MimeType}s.
|
||||
*/
|
||||
protected AbstractJacksonDecoder(ObjectMapper mapper, MimeType... mimeTypes) {
|
||||
protected AbstractJacksonDecoder(T mapper, MimeType... mimeTypes) {
|
||||
super(mapper, mimeTypes);
|
||||
}
|
||||
|
||||
@@ -104,7 +105,7 @@ public abstract class AbstractJacksonDecoder extends JacksonCodecSupport impleme
|
||||
if (!supportsMimeType(mimeType)) {
|
||||
return false;
|
||||
}
|
||||
ObjectMapper mapper = selectObjectMapper(elementType, mimeType);
|
||||
T mapper = selectMapper(elementType, mimeType);
|
||||
if (mapper == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -115,7 +116,7 @@ public abstract class AbstractJacksonDecoder extends JacksonCodecSupport impleme
|
||||
public Flux<Object> decode(Publisher<DataBuffer> input, ResolvableType elementType,
|
||||
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
|
||||
|
||||
ObjectMapper mapper = selectObjectMapper(elementType, mimeType);
|
||||
T mapper = selectMapper(elementType, mimeType);
|
||||
if (mapper == null) {
|
||||
return Flux.error(new IllegalStateException("No ObjectMapper for " + elementType));
|
||||
}
|
||||
@@ -141,7 +142,7 @@ public abstract class AbstractJacksonDecoder extends JacksonCodecSupport impleme
|
||||
|
||||
return tokens.handle((tokenBuffer, sink) -> {
|
||||
try {
|
||||
Object value = reader.readValue(tokenBuffer.asParser(getObjectMapper()._deserializationContext()));
|
||||
Object value = reader.readValue(tokenBuffer.asParser(getMapper()._deserializationContext()));
|
||||
logValue(value, hints);
|
||||
if (value != null) {
|
||||
sink.next(value);
|
||||
@@ -189,7 +190,7 @@ public abstract class AbstractJacksonDecoder extends JacksonCodecSupport impleme
|
||||
public Object decode(DataBuffer dataBuffer, ResolvableType targetType,
|
||||
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) throws DecodingException {
|
||||
|
||||
ObjectMapper mapper = selectObjectMapper(targetType, mimeType);
|
||||
T mapper = selectMapper(targetType, mimeType);
|
||||
if (mapper == null) {
|
||||
throw new IllegalStateException("No ObjectMapper for " + targetType);
|
||||
}
|
||||
@@ -208,8 +209,7 @@ public abstract class AbstractJacksonDecoder extends JacksonCodecSupport impleme
|
||||
}
|
||||
}
|
||||
|
||||
private ObjectReader createObjectReader(
|
||||
ObjectMapper mapper, ResolvableType elementType, @Nullable Map<String, Object> hints) {
|
||||
private ObjectReader createObjectReader(T mapper, ResolvableType elementType, @Nullable Map<String, Object> hints) {
|
||||
|
||||
Assert.notNull(elementType, "'elementType' must not be null");
|
||||
Class<?> contextClass = getContextClass(elementType);
|
||||
|
||||
@@ -64,8 +64,9 @@ import org.springframework.util.MimeType;
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 7.0
|
||||
* @param <T> the type of {@link ObjectMapper}
|
||||
*/
|
||||
public abstract class AbstractJacksonEncoder extends JacksonCodecSupport implements HttpMessageEncoder<Object> {
|
||||
public abstract class AbstractJacksonEncoder<T extends ObjectMapper> extends JacksonCodecSupport<T> implements HttpMessageEncoder<Object> {
|
||||
|
||||
private static final byte[] NEWLINE_SEPARATOR = {'\n'};
|
||||
|
||||
@@ -90,14 +91,14 @@ public abstract class AbstractJacksonEncoder extends JacksonCodecSupport impleme
|
||||
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
||||
* by {@link MapperBuilder#findModules(ClassLoader)} and {@link MimeType}s.
|
||||
*/
|
||||
protected AbstractJacksonEncoder(MapperBuilder<?, ?> builder, MimeType... mimeTypes) {
|
||||
protected AbstractJacksonEncoder(MapperBuilder<T, ?> builder, MimeType... mimeTypes) {
|
||||
super(builder, mimeTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new instance with the provided {@link ObjectMapper} and {@link MimeType}s.
|
||||
*/
|
||||
protected AbstractJacksonEncoder(ObjectMapper mapper, MimeType... mimeTypes) {
|
||||
protected AbstractJacksonEncoder(T mapper, MimeType... mimeTypes) {
|
||||
super(mapper, mimeTypes);
|
||||
}
|
||||
|
||||
@@ -122,7 +123,7 @@ public abstract class AbstractJacksonEncoder extends JacksonCodecSupport impleme
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (this.objectMapperRegistrations != null && selectObjectMapper(elementType, mimeType) == null) {
|
||||
if (this.mapperRegistrations != null && selectMapper(elementType, mimeType) == null) {
|
||||
return false;
|
||||
}
|
||||
Class<?> clazz = elementType.resolve();
|
||||
@@ -155,7 +156,7 @@ public abstract class AbstractJacksonEncoder extends JacksonCodecSupport impleme
|
||||
}
|
||||
|
||||
try {
|
||||
ObjectMapper mapper = selectObjectMapper(elementType, mimeType);
|
||||
T mapper = selectMapper(elementType, mimeType);
|
||||
if (mapper == null) {
|
||||
throw new IllegalStateException("No ObjectMapper for " + elementType);
|
||||
}
|
||||
@@ -225,7 +226,7 @@ public abstract class AbstractJacksonEncoder extends JacksonCodecSupport impleme
|
||||
filters = (FilterProvider) hints.get(FILTER_PROVIDER_HINT);
|
||||
}
|
||||
|
||||
ObjectMapper mapper = selectObjectMapper(valueType, mimeType);
|
||||
T mapper = selectMapper(valueType, mimeType);
|
||||
if (mapper == null) {
|
||||
throw new IllegalStateException("No ObjectMapper for " + valueType);
|
||||
}
|
||||
@@ -319,7 +320,7 @@ public abstract class AbstractJacksonEncoder extends JacksonCodecSupport impleme
|
||||
}
|
||||
|
||||
private ObjectWriter createObjectWriter(
|
||||
ObjectMapper mapper, ResolvableType valueType, @Nullable MimeType mimeType,
|
||||
T mapper, ResolvableType valueType, @Nullable MimeType mimeType,
|
||||
@Nullable Class<?> jsonView, @Nullable Map<String, Object> hints) {
|
||||
|
||||
JavaType javaType = getJavaType(valueType.getType(), null);
|
||||
|
||||
@@ -50,12 +50,13 @@ import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
/**
|
||||
* Base class providing support methods for Jackson 2.x encoding and decoding.
|
||||
* Base class providing support methods for Jackson 3.x encoding and decoding.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 7.0
|
||||
* @param <T> the type of {@link ObjectMapper}
|
||||
*/
|
||||
public abstract class JacksonCodecSupport {
|
||||
public abstract class JacksonCodecSupport<T extends ObjectMapper> {
|
||||
|
||||
/**
|
||||
* The key for the hint to specify a "JSON View" for encoding or decoding
|
||||
@@ -83,9 +84,9 @@ public abstract class JacksonCodecSupport {
|
||||
|
||||
protected final Log logger = HttpLogging.forLogName(getClass());
|
||||
|
||||
private final ObjectMapper defaultObjectMapper;
|
||||
private final T defaultMapper;
|
||||
|
||||
protected @Nullable Map<Class<?>, Map<MimeType, ObjectMapper>> objectMapperRegistrations;
|
||||
protected @Nullable Map<Class<?>, Map<MimeType, T>> mapperRegistrations;
|
||||
|
||||
private final List<MimeType> mimeTypes;
|
||||
|
||||
@@ -96,10 +97,10 @@ public abstract class JacksonCodecSupport {
|
||||
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
||||
* by {@link MapperBuilder#findModules(ClassLoader)} and {@link MimeType}s.
|
||||
*/
|
||||
protected JacksonCodecSupport(MapperBuilder<?, ?> builder, MimeType... mimeTypes) {
|
||||
protected JacksonCodecSupport(MapperBuilder<T, ?> builder, MimeType... mimeTypes) {
|
||||
Assert.notNull(builder, "MapperBuilder must not be null");
|
||||
Assert.notEmpty(mimeTypes, "MimeTypes must not be empty");
|
||||
this.defaultObjectMapper = builder.addModules(initModules()).build();
|
||||
this.defaultMapper = builder.addModules(initModules()).build();
|
||||
this.mimeTypes = List.of(mimeTypes);
|
||||
}
|
||||
|
||||
@@ -108,10 +109,10 @@ public abstract class JacksonCodecSupport {
|
||||
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
||||
* by {@link MapperBuilder#findModules(ClassLoader)} and {@link MimeType}s.
|
||||
*/
|
||||
protected JacksonCodecSupport(ObjectMapper objectMapper, MimeType... mimeTypes) {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
||||
protected JacksonCodecSupport(T mapper, MimeType... mimeTypes) {
|
||||
Assert.notNull(mapper, "ObjectMapper must not be null");
|
||||
Assert.notEmpty(mimeTypes, "MimeTypes must not be empty");
|
||||
this.defaultObjectMapper = objectMapper;
|
||||
this.defaultMapper = mapper;
|
||||
this.mimeTypes = List.of(mimeTypes);
|
||||
}
|
||||
|
||||
@@ -124,19 +125,19 @@ public abstract class JacksonCodecSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link ObjectMapper configured} default ObjectMapper.
|
||||
* Return the {@link ObjectMapper configured} default mapper.
|
||||
*/
|
||||
public ObjectMapper getObjectMapper() {
|
||||
return this.defaultObjectMapper;
|
||||
public T getMapper() {
|
||||
return this.defaultMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the {@link ObjectMapper} instances to use for the given
|
||||
* {@link Class}. This is useful when you want to deviate from the
|
||||
* {@link #getObjectMapper() default} ObjectMapper or have the
|
||||
* {@link #getMapper() default} ObjectMapper or have the
|
||||
* {@code ObjectMapper} vary by {@code MediaType}.
|
||||
* <p><strong>Note:</strong> Use of this method effectively turns off use of
|
||||
* the default {@link #getObjectMapper() ObjectMapper} and supported
|
||||
* the default {@link #getMapper() ObjectMapper} and supported
|
||||
* {@link #getMimeTypes() MimeTypes} for the given class. Therefore it is
|
||||
* important for the mappings configured here to
|
||||
* {@link MediaType#includes(MediaType) include} every MediaType that must
|
||||
@@ -145,12 +146,12 @@ public abstract class JacksonCodecSupport {
|
||||
* @param registrar a consumer to populate or otherwise update the
|
||||
* MediaType-to-ObjectMapper associations for the given Class
|
||||
*/
|
||||
public void registerObjectMappersForType(Class<?> clazz, Consumer<Map<MimeType, ObjectMapper>> registrar) {
|
||||
if (this.objectMapperRegistrations == null) {
|
||||
this.objectMapperRegistrations = new LinkedHashMap<>();
|
||||
public void registerMappersForType(Class<?> clazz, Consumer<Map<MimeType, T>> registrar) {
|
||||
if (this.mapperRegistrations == null) {
|
||||
this.mapperRegistrations = new LinkedHashMap<>();
|
||||
}
|
||||
Map<MimeType, ObjectMapper> registrations =
|
||||
this.objectMapperRegistrations.computeIfAbsent(clazz, c -> new LinkedHashMap<>());
|
||||
Map<MimeType, T> registrations =
|
||||
this.mapperRegistrations.computeIfAbsent(clazz, c -> new LinkedHashMap<>());
|
||||
registrar.accept(registrations);
|
||||
}
|
||||
|
||||
@@ -160,8 +161,8 @@ public abstract class JacksonCodecSupport {
|
||||
* @return a map with registered MediaType-to-ObjectMapper registrations,
|
||||
* or empty if in case of no registrations for the given class.
|
||||
*/
|
||||
public @Nullable Map<MimeType, ObjectMapper> getObjectMappersForType(Class<?> clazz) {
|
||||
for (Map.Entry<Class<?>, Map<MimeType, ObjectMapper>> entry : getObjectMapperRegistrations().entrySet()) {
|
||||
public @Nullable Map<MimeType, T> getMappersForType(Class<?> clazz) {
|
||||
for (Map.Entry<Class<?>, Map<MimeType, T>> entry : getMapperRegistrations().entrySet()) {
|
||||
if (entry.getKey().isAssignableFrom(clazz)) {
|
||||
return entry.getValue();
|
||||
}
|
||||
@@ -169,8 +170,8 @@ public abstract class JacksonCodecSupport {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
protected Map<Class<?>, Map<MimeType, ObjectMapper>> getObjectMapperRegistrations() {
|
||||
return (this.objectMapperRegistrations != null ? this.objectMapperRegistrations : Collections.emptyMap());
|
||||
protected Map<Class<?>, Map<MimeType, T>> getMapperRegistrations() {
|
||||
return (this.mapperRegistrations != null ? this.mapperRegistrations : Collections.emptyMap());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -183,7 +184,7 @@ public abstract class JacksonCodecSupport {
|
||||
protected List<MimeType> getMimeTypes(ResolvableType elementType) {
|
||||
Class<?> elementClass = elementType.toClass();
|
||||
List<MimeType> result = null;
|
||||
for (Map.Entry<Class<?>, Map<MimeType, ObjectMapper>> entry : getObjectMapperRegistrations().entrySet()) {
|
||||
for (Map.Entry<Class<?>, Map<MimeType, T>> entry : getMapperRegistrations().entrySet()) {
|
||||
if (entry.getKey().isAssignableFrom(elementClass)) {
|
||||
result = (result != null ? result : new ArrayList<>(entry.getValue().size()));
|
||||
result.addAll(entry.getValue().keySet());
|
||||
@@ -216,7 +217,7 @@ public abstract class JacksonCodecSupport {
|
||||
}
|
||||
|
||||
protected JavaType getJavaType(Type type, @Nullable Class<?> contextClass) {
|
||||
return this.defaultObjectMapper.constructType(GenericTypeResolver.resolveType(type, contextClass));
|
||||
return this.defaultMapper.constructType(GenericTypeResolver.resolveType(type, contextClass));
|
||||
}
|
||||
|
||||
protected Map<String, Object> getHints(ResolvableType resolvableType) {
|
||||
@@ -250,18 +251,18 @@ public abstract class JacksonCodecSupport {
|
||||
/**
|
||||
* Select an ObjectMapper to use, either the main ObjectMapper or another
|
||||
* if the handling for the given Class has been customized through
|
||||
* {@link #registerObjectMappersForType(Class, Consumer)}.
|
||||
* {@link #registerMappersForType(Class, Consumer)}.
|
||||
*/
|
||||
protected @Nullable ObjectMapper selectObjectMapper(ResolvableType targetType, @Nullable MimeType targetMimeType) {
|
||||
if (targetMimeType == null || CollectionUtils.isEmpty(this.objectMapperRegistrations)) {
|
||||
return this.defaultObjectMapper;
|
||||
protected @Nullable T selectMapper(ResolvableType targetType, @Nullable MimeType targetMimeType) {
|
||||
if (targetMimeType == null || CollectionUtils.isEmpty(this.mapperRegistrations)) {
|
||||
return this.defaultMapper;
|
||||
}
|
||||
Class<?> targetClass = targetType.toClass();
|
||||
for (Map.Entry<Class<?>, Map<MimeType, ObjectMapper>> typeEntry : getObjectMapperRegistrations().entrySet()) {
|
||||
for (Map.Entry<Class<?>, Map<MimeType, T>> typeEntry : getMapperRegistrations().entrySet()) {
|
||||
if (typeEntry.getKey().isAssignableFrom(targetClass)) {
|
||||
for (Map.Entry<MimeType, ObjectMapper> objectMapperEntry : typeEntry.getValue().entrySet()) {
|
||||
if (objectMapperEntry.getKey().includes(targetMimeType)) {
|
||||
return objectMapperEntry.getValue();
|
||||
for (Map.Entry<MimeType, T> mapperEntry : typeEntry.getValue().entrySet()) {
|
||||
if (mapperEntry.getKey().includes(targetMimeType)) {
|
||||
return mapperEntry.getValue();
|
||||
}
|
||||
}
|
||||
// No matching registrations
|
||||
@@ -269,7 +270,7 @@ public abstract class JacksonCodecSupport {
|
||||
}
|
||||
}
|
||||
// No registrations
|
||||
return this.defaultObjectMapper;
|
||||
return this.defaultMapper;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ import org.springframework.util.MimeType;
|
||||
* @see JacksonCborEncoder
|
||||
* @see <a href="https://github.com/spring-projects/spring-framework/issues/20513">Add CBOR support to WebFlux</a>
|
||||
*/
|
||||
public class JacksonCborDecoder extends AbstractJacksonDecoder {
|
||||
public class JacksonCborDecoder extends AbstractJacksonDecoder<CBORMapper> {
|
||||
|
||||
/**
|
||||
* Construct a new instance with a {@link CBORMapper} customized with the
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ import org.springframework.util.MimeType;
|
||||
* @see JacksonCborDecoder
|
||||
* @see <a href="https://github.com/spring-projects/spring-framework/issues/20513">Add CBOR support to WebFlux</a>
|
||||
*/
|
||||
public class JacksonCborEncoder extends AbstractJacksonEncoder {
|
||||
public class JacksonCborEncoder extends AbstractJacksonEncoder<CBORMapper> {
|
||||
|
||||
/**
|
||||
* Construct a new instance with a {@link CBORMapper} customized with the
|
||||
|
||||
+5
-6
@@ -25,7 +25,6 @@ import java.util.Map;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.cfg.MapperBuilder;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
@@ -50,7 +49,7 @@ import org.springframework.util.MimeTypeUtils;
|
||||
* @since 7.0
|
||||
* @see JacksonJsonEncoder
|
||||
*/
|
||||
public class JacksonJsonDecoder extends AbstractJacksonDecoder {
|
||||
public class JacksonJsonDecoder extends AbstractJacksonDecoder<JsonMapper> {
|
||||
|
||||
private static final CharBufferDecoder CHAR_BUFFER_DECODER = CharBufferDecoder.textPlainOnly(Arrays.asList(",", "\n"), false);
|
||||
|
||||
@@ -73,20 +72,20 @@ public class JacksonJsonDecoder extends AbstractJacksonDecoder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new instance with the provided {@link ObjectMapper}.
|
||||
* Construct a new instance with the provided {@link JsonMapper}.
|
||||
* @see JsonMapper#builder()
|
||||
* @see MapperBuilder#findModules(ClassLoader)
|
||||
*/
|
||||
public JacksonJsonDecoder(ObjectMapper mapper) {
|
||||
public JacksonJsonDecoder(JsonMapper mapper) {
|
||||
this(mapper, DEFAULT_JSON_MIME_TYPES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new instance with the provided {@link ObjectMapper} and {@link MimeType}s.
|
||||
* Construct a new instance with the provided {@link JsonMapper} and {@link MimeType}s.
|
||||
* @see JsonMapper#builder()
|
||||
* @see MapperBuilder#findModules(ClassLoader)
|
||||
*/
|
||||
public JacksonJsonDecoder(ObjectMapper mapper, MimeType... mimeTypes) {
|
||||
public JacksonJsonDecoder(JsonMapper mapper, MimeType... mimeTypes) {
|
||||
super(mapper, mimeTypes);
|
||||
}
|
||||
|
||||
|
||||
+5
-6
@@ -25,7 +25,6 @@ import reactor.core.publisher.Flux;
|
||||
import tools.jackson.core.PrettyPrinter;
|
||||
import tools.jackson.core.util.DefaultIndenter;
|
||||
import tools.jackson.core.util.DefaultPrettyPrinter;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.ObjectWriter;
|
||||
import tools.jackson.databind.SerializationFeature;
|
||||
import tools.jackson.databind.cfg.MapperBuilder;
|
||||
@@ -51,7 +50,7 @@ import org.springframework.util.MimeType;
|
||||
* @since 7.0
|
||||
* @see JacksonJsonDecoder
|
||||
*/
|
||||
public class JacksonJsonEncoder extends AbstractJacksonEncoder {
|
||||
public class JacksonJsonEncoder extends AbstractJacksonEncoder<JsonMapper> {
|
||||
|
||||
private static final List<MimeType> problemDetailMimeTypes =
|
||||
Collections.singletonList(MediaType.APPLICATION_PROBLEM_JSON);
|
||||
@@ -80,21 +79,21 @@ public class JacksonJsonEncoder extends AbstractJacksonEncoder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new instance with the provided {@link ObjectMapper}.
|
||||
* Construct a new instance with the provided {@link JsonMapper}.
|
||||
* @see JsonMapper#builder()
|
||||
* @see MapperBuilder#findModules(ClassLoader)
|
||||
*/
|
||||
public JacksonJsonEncoder(ObjectMapper mapper) {
|
||||
public JacksonJsonEncoder(JsonMapper mapper) {
|
||||
this(mapper, DEFAULT_JSON_MIME_TYPES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new instance with the provided {@link ObjectMapper} and
|
||||
* Construct a new instance with the provided {@link JsonMapper} and
|
||||
* {@link MimeType}s.
|
||||
* @see JsonMapper#builder()
|
||||
* @see MapperBuilder#findModules(ClassLoader)
|
||||
*/
|
||||
public JacksonJsonEncoder(ObjectMapper mapper, MimeType... mimeTypes) {
|
||||
public JacksonJsonEncoder(JsonMapper mapper, MimeType... mimeTypes) {
|
||||
super(mapper, mimeTypes);
|
||||
setStreamingMediaTypes(List.of(MediaType.APPLICATION_NDJSON));
|
||||
this.ssePrettyPrinter = initSsePrettyPrinter();
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ import org.springframework.util.MimeType;
|
||||
* @since 7.0
|
||||
* @see JacksonSmileEncoder
|
||||
*/
|
||||
public class JacksonSmileDecoder extends AbstractJacksonDecoder {
|
||||
public class JacksonSmileDecoder extends AbstractJacksonDecoder<SmileMapper> {
|
||||
|
||||
private static final MimeType[] DEFAULT_SMILE_MIME_TYPES = new MimeType[] {
|
||||
new MimeType("application", "x-jackson-smile"),
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ import org.springframework.util.MimeType;
|
||||
* @since 7.0
|
||||
* @see JacksonSmileDecoder
|
||||
*/
|
||||
public class JacksonSmileEncoder extends AbstractJacksonEncoder {
|
||||
public class JacksonSmileEncoder extends AbstractJacksonEncoder<SmileMapper> {
|
||||
|
||||
private static final MimeType[] DEFAULT_SMILE_MIME_TYPES = new MimeType[] {
|
||||
new MimeType("application", "x-jackson-smile"),
|
||||
|
||||
+1
-1
@@ -527,7 +527,7 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
|
||||
}
|
||||
}
|
||||
if (jacksonPresent) {
|
||||
if (codec instanceof AbstractJacksonDecoder abstractJacksonDecoder) {
|
||||
if (codec instanceof AbstractJacksonDecoder<?> abstractJacksonDecoder) {
|
||||
abstractJacksonDecoder.setMaxInMemorySize(size);
|
||||
}
|
||||
}
|
||||
|
||||
+47
-46
@@ -82,9 +82,10 @@ import org.springframework.util.TypeUtils;
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 7.0
|
||||
* @param <T> the type of {@link ObjectMapper}
|
||||
* @see JacksonJsonHttpMessageConverter
|
||||
*/
|
||||
public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartHttpMessageConverter<Object> {
|
||||
public abstract class AbstractJacksonHttpMessageConverter<T extends ObjectMapper> extends AbstractSmartHttpMessageConverter<Object> {
|
||||
|
||||
private static final String JSON_VIEW_HINT = JsonView.class.getName();
|
||||
|
||||
@@ -103,9 +104,9 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||
}
|
||||
|
||||
|
||||
protected final ObjectMapper defaultObjectMapper;
|
||||
protected final T defaultMapper;
|
||||
|
||||
private @Nullable Map<Class<?>, Map<MediaType, ObjectMapper>> objectMapperRegistrations;
|
||||
private @Nullable Map<Class<?>, Map<MediaType, T>> mapperRegistrations;
|
||||
|
||||
private final @Nullable PrettyPrinter ssePrettyPrinter;
|
||||
|
||||
@@ -115,8 +116,8 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
||||
* by {@link MapperBuilder#findModules(ClassLoader)}.
|
||||
*/
|
||||
private AbstractJacksonHttpMessageConverter(MapperBuilder<?, ?> builder) {
|
||||
this.defaultObjectMapper = builder.addModules(initModules()).build();
|
||||
private AbstractJacksonHttpMessageConverter(MapperBuilder<T, ?> builder) {
|
||||
this.defaultMapper = builder.addModules(initModules()).build();
|
||||
this.ssePrettyPrinter = initSsePrettyPrinter();
|
||||
}
|
||||
|
||||
@@ -125,7 +126,7 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
||||
* by {@link MapperBuilder#findModules(ClassLoader)} and {@link MediaType}.
|
||||
*/
|
||||
protected AbstractJacksonHttpMessageConverter(MapperBuilder<?, ?> builder, MediaType supportedMediaType) {
|
||||
protected AbstractJacksonHttpMessageConverter(MapperBuilder<T, ?> builder, MediaType supportedMediaType) {
|
||||
this(builder);
|
||||
setSupportedMediaTypes(Collections.singletonList(supportedMediaType));
|
||||
}
|
||||
@@ -135,7 +136,7 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
||||
* by {@link MapperBuilder#findModules(ClassLoader)} and {@link MediaType}s.
|
||||
*/
|
||||
protected AbstractJacksonHttpMessageConverter(MapperBuilder<?, ?> builder, MediaType... supportedMediaTypes) {
|
||||
protected AbstractJacksonHttpMessageConverter(MapperBuilder<T, ?> builder, MediaType... supportedMediaTypes) {
|
||||
this(builder);
|
||||
setSupportedMediaTypes(Arrays.asList(supportedMediaTypes));
|
||||
}
|
||||
@@ -143,24 +144,24 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||
/**
|
||||
* Construct a new instance with the provided {@link ObjectMapper}.
|
||||
*/
|
||||
protected AbstractJacksonHttpMessageConverter(ObjectMapper objectMapper) {
|
||||
this.defaultObjectMapper = objectMapper;
|
||||
protected AbstractJacksonHttpMessageConverter(T mapper) {
|
||||
this.defaultMapper = mapper;
|
||||
this.ssePrettyPrinter = initSsePrettyPrinter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new instance with the provided {@link ObjectMapper} and {@link MediaType}.
|
||||
*/
|
||||
protected AbstractJacksonHttpMessageConverter(ObjectMapper objectMapper, MediaType supportedMediaType) {
|
||||
this(objectMapper);
|
||||
protected AbstractJacksonHttpMessageConverter(T mapper, MediaType supportedMediaType) {
|
||||
this(mapper);
|
||||
setSupportedMediaTypes(Collections.singletonList(supportedMediaType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new instance with the provided {@link ObjectMapper} and {@link MediaType}s.
|
||||
*/
|
||||
protected AbstractJacksonHttpMessageConverter(ObjectMapper objectMapper, MediaType... supportedMediaTypes) {
|
||||
this(objectMapper);
|
||||
protected AbstractJacksonHttpMessageConverter(T mapper, MediaType... supportedMediaTypes) {
|
||||
this(mapper);
|
||||
setSupportedMediaTypes(Arrays.asList(supportedMediaTypes));
|
||||
}
|
||||
|
||||
@@ -184,19 +185,19 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the main {@code ObjectMapper} in use.
|
||||
* Return the main {@link ObjectMapper} in use.
|
||||
*/
|
||||
public ObjectMapper getObjectMapper() {
|
||||
return this.defaultObjectMapper;
|
||||
public T getMapper() {
|
||||
return this.defaultMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the {@link ObjectMapper} instances to use for the given
|
||||
* {@link Class}. This is useful when you want to deviate from the
|
||||
* {@link #getObjectMapper() default} ObjectMapper or have the
|
||||
* {@link #getMapper() default} ObjectMapper or have the
|
||||
* {@code ObjectMapper} vary by {@code MediaType}.
|
||||
* <p><strong>Note:</strong> Use of this method effectively turns off use of
|
||||
* the default {@link #getObjectMapper() ObjectMapper} and
|
||||
* the default {@link #getMapper() ObjectMapper} and
|
||||
* {@link #setSupportedMediaTypes(List) supportedMediaTypes} for the given
|
||||
* class. Therefore it is important for the mappings configured here to
|
||||
* {@link MediaType#includes(MediaType) include} every MediaType that must
|
||||
@@ -205,12 +206,12 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||
* @param registrar a consumer to populate or otherwise update the
|
||||
* MediaType-to-ObjectMapper associations for the given Class
|
||||
*/
|
||||
public void registerObjectMappersForType(Class<?> clazz, Consumer<Map<MediaType, ObjectMapper>> registrar) {
|
||||
if (this.objectMapperRegistrations == null) {
|
||||
this.objectMapperRegistrations = new LinkedHashMap<>();
|
||||
public void registerMappersForType(Class<?> clazz, Consumer<Map<MediaType, T>> registrar) {
|
||||
if (this.mapperRegistrations == null) {
|
||||
this.mapperRegistrations = new LinkedHashMap<>();
|
||||
}
|
||||
Map<MediaType, ObjectMapper> registrations =
|
||||
this.objectMapperRegistrations.computeIfAbsent(clazz, c -> new LinkedHashMap<>());
|
||||
Map<MediaType, T> registrations =
|
||||
this.mapperRegistrations.computeIfAbsent(clazz, c -> new LinkedHashMap<>());
|
||||
registrar.accept(registrations);
|
||||
}
|
||||
|
||||
@@ -220,8 +221,8 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||
* @return a map with registered MediaType-to-ObjectMapper registrations,
|
||||
* or empty if in case of no registrations for the given class.
|
||||
*/
|
||||
public Map<MediaType, ObjectMapper> getObjectMappersForType(Class<?> clazz) {
|
||||
for (Map.Entry<Class<?>, Map<MediaType, ObjectMapper>> entry : getObjectMapperRegistrations().entrySet()) {
|
||||
public Map<MediaType, T> getMappersForType(Class<?> clazz) {
|
||||
for (Map.Entry<Class<?>, Map<MediaType, T>> entry : getMapperRegistrations().entrySet()) {
|
||||
if (entry.getKey().isAssignableFrom(clazz)) {
|
||||
return entry.getValue();
|
||||
}
|
||||
@@ -232,7 +233,7 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||
@Override
|
||||
public List<MediaType> getSupportedMediaTypes(Class<?> clazz) {
|
||||
List<MediaType> result = null;
|
||||
for (Map.Entry<Class<?>, Map<MediaType, ObjectMapper>> entry : getObjectMapperRegistrations().entrySet()) {
|
||||
for (Map.Entry<Class<?>, Map<MediaType, T>> entry : getMapperRegistrations().entrySet()) {
|
||||
if (entry.getKey().isAssignableFrom(clazz)) {
|
||||
result = (result != null ? result : new ArrayList<>(entry.getValue().size()));
|
||||
result.addAll(entry.getValue().keySet());
|
||||
@@ -245,8 +246,8 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||
getMediaTypesForProblemDetail() : getSupportedMediaTypes());
|
||||
}
|
||||
|
||||
private Map<Class<?>, Map<MediaType, ObjectMapper>> getObjectMapperRegistrations() {
|
||||
return (this.objectMapperRegistrations != null ? this.objectMapperRegistrations : Collections.emptyMap());
|
||||
private Map<Class<?>, Map<MediaType, T>> getMapperRegistrations() {
|
||||
return (this.mapperRegistrations != null ? this.mapperRegistrations : Collections.emptyMap());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -267,7 +268,7 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||
if (clazz == null) {
|
||||
return false;
|
||||
}
|
||||
return this.objectMapperRegistrations == null || selectObjectMapper(clazz, mediaType) != null;
|
||||
return this.mapperRegistrations == null || selectMapper(clazz, mediaType) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -285,23 +286,23 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||
if (MappingJacksonValue.class.isAssignableFrom(clazz)) {
|
||||
throw new UnsupportedOperationException("MappingJacksonValue is not supported, use hints instead");
|
||||
}
|
||||
return this.objectMapperRegistrations == null || selectObjectMapper(clazz, mediaType) != null;
|
||||
return this.mapperRegistrations == null || selectMapper(clazz, mediaType) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select an ObjectMapper to use, either the main ObjectMapper or another
|
||||
* if the handling for the given Class has been customized through
|
||||
* {@link #registerObjectMappersForType(Class, Consumer)}.
|
||||
* {@link #registerMappersForType(Class, Consumer)}.
|
||||
*/
|
||||
private @Nullable ObjectMapper selectObjectMapper(Class<?> targetType, @Nullable MediaType targetMediaType) {
|
||||
if (targetMediaType == null || CollectionUtils.isEmpty(this.objectMapperRegistrations)) {
|
||||
return this.defaultObjectMapper;
|
||||
private @Nullable T selectMapper(Class<?> targetType, @Nullable MediaType targetMediaType) {
|
||||
if (targetMediaType == null || CollectionUtils.isEmpty(this.mapperRegistrations)) {
|
||||
return this.defaultMapper;
|
||||
}
|
||||
for (Map.Entry<Class<?>, Map<MediaType, ObjectMapper>> typeEntry : getObjectMapperRegistrations().entrySet()) {
|
||||
for (Map.Entry<Class<?>, Map<MediaType, T>> typeEntry : getMapperRegistrations().entrySet()) {
|
||||
if (typeEntry.getKey().isAssignableFrom(targetType)) {
|
||||
for (Map.Entry<MediaType, ObjectMapper> objectMapperEntry : typeEntry.getValue().entrySet()) {
|
||||
if (objectMapperEntry.getKey().includes(targetMediaType)) {
|
||||
return objectMapperEntry.getValue();
|
||||
for (Map.Entry<MediaType, T> mapperEntry : typeEntry.getValue().entrySet()) {
|
||||
if (mapperEntry.getKey().includes(targetMediaType)) {
|
||||
return mapperEntry.getValue();
|
||||
}
|
||||
}
|
||||
// No matching registrations
|
||||
@@ -309,7 +310,7 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||
}
|
||||
}
|
||||
// No registrations
|
||||
return this.defaultObjectMapper;
|
||||
return this.defaultMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -334,8 +335,8 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||
MediaType contentType = inputMessage.getHeaders().getContentType();
|
||||
Charset charset = getCharset(contentType);
|
||||
|
||||
ObjectMapper objectMapper = selectObjectMapper(javaType.getRawClass(), contentType);
|
||||
Assert.state(objectMapper != null, () -> "No ObjectMapper for " + javaType);
|
||||
T mapper = selectMapper(javaType.getRawClass(), contentType);
|
||||
Assert.state(mapper != null, () -> "No ObjectMapper for " + javaType);
|
||||
|
||||
boolean isUnicode = ENCODINGS.containsKey(charset.name()) ||
|
||||
"UTF-16".equals(charset.name()) ||
|
||||
@@ -345,7 +346,7 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||
if (inputMessage instanceof MappingJacksonInputMessage) {
|
||||
throw new UnsupportedOperationException("MappingJacksonInputMessage is not supported, use hints instead");
|
||||
}
|
||||
ObjectReader objectReader = objectMapper.readerFor(javaType);
|
||||
ObjectReader objectReader = mapper.readerFor(javaType);
|
||||
if (hints != null && hints.containsKey(JSON_VIEW_HINT)) {
|
||||
objectReader = objectReader.withView((Class<?>) hints.get(JSON_VIEW_HINT));
|
||||
}
|
||||
@@ -401,8 +402,8 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||
JsonEncoding encoding = getJsonEncoding(contentType);
|
||||
|
||||
Class<?> clazz = object.getClass();
|
||||
ObjectMapper objectMapper = selectObjectMapper(clazz, contentType);
|
||||
Assert.state(objectMapper != null, () -> "No ObjectMapper for " + clazz.getName());
|
||||
T mapper = selectMapper(clazz, contentType);
|
||||
Assert.state(mapper != null, () -> "No ObjectMapper for " + clazz.getName());
|
||||
|
||||
OutputStream outputStream = StreamUtils.nonClosing(outputMessage.getBody());
|
||||
Class<?> jsonView = null;
|
||||
@@ -419,7 +420,7 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||
}
|
||||
|
||||
ObjectWriter objectWriter = (jsonView != null ?
|
||||
objectMapper.writerWithView(jsonView) : objectMapper.writer());
|
||||
mapper.writerWithView(jsonView) : mapper.writer());
|
||||
if (filters != null) {
|
||||
objectWriter = objectWriter.with(filters);
|
||||
}
|
||||
@@ -485,7 +486,7 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||
* @return the Jackson JavaType
|
||||
*/
|
||||
protected JavaType getJavaType(Type type, @Nullable Class<?> contextClass) {
|
||||
return this.defaultObjectMapper.constructType(GenericTypeResolver.resolveType(type, contextClass));
|
||||
return this.defaultMapper.constructType(GenericTypeResolver.resolveType(type, contextClass));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ import org.springframework.http.converter.AbstractJacksonHttpMessageConverter;
|
||||
* @author Sebastien Deleuze
|
||||
* @since 7.0
|
||||
*/
|
||||
public class JacksonCborHttpMessageConverter extends AbstractJacksonHttpMessageConverter {
|
||||
public class JacksonCborHttpMessageConverter extends AbstractJacksonHttpMessageConverter<CBORMapper> {
|
||||
|
||||
/**
|
||||
* Construct a new instance with a {@link CBORMapper} customized with the
|
||||
|
||||
+4
-5
@@ -21,7 +21,6 @@ import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.core.JsonGenerator;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.cfg.MapperBuilder;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
@@ -32,7 +31,7 @@ import org.springframework.http.converter.AbstractJacksonHttpMessageConverter;
|
||||
/**
|
||||
* Implementation of {@link org.springframework.http.converter.HttpMessageConverter}
|
||||
* that can read and write JSON using <a href="https://github.com/FasterXML/jackson">Jackson 3.x's</a>
|
||||
* {@link ObjectMapper}.
|
||||
* {@link JsonMapper}.
|
||||
*
|
||||
* <p>This converter can be used to bind to typed beans, or untyped
|
||||
* {@code HashMap} instances.
|
||||
@@ -56,7 +55,7 @@ import org.springframework.http.converter.AbstractJacksonHttpMessageConverter;
|
||||
* @author Sebastien Deleuze
|
||||
* @since 7.0
|
||||
*/
|
||||
public class JacksonJsonHttpMessageConverter extends AbstractJacksonHttpMessageConverter {
|
||||
public class JacksonJsonHttpMessageConverter extends AbstractJacksonHttpMessageConverter<JsonMapper> {
|
||||
|
||||
private static final List<MediaType> problemDetailMediaTypes =
|
||||
Collections.singletonList(MediaType.APPLICATION_PROBLEM_JSON);
|
||||
@@ -79,11 +78,11 @@ public class JacksonJsonHttpMessageConverter extends AbstractJacksonHttpMessageC
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new instance with the provided {@link ObjectMapper}.
|
||||
* Construct a new instance with the provided {@link JsonMapper}.
|
||||
* @see JsonMapper#builder()
|
||||
* @see MapperBuilder#findModules(ClassLoader)
|
||||
*/
|
||||
public JacksonJsonHttpMessageConverter(ObjectMapper objectMapper) {
|
||||
public JacksonJsonHttpMessageConverter(JsonMapper objectMapper) {
|
||||
super(objectMapper, DEFAULT_JSON_MIME_TYPES);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ import org.springframework.http.converter.AbstractJacksonHttpMessageConverter;
|
||||
* @author Sebastien Deleuze
|
||||
* @since 7.0
|
||||
*/
|
||||
public class JacksonSmileHttpMessageConverter extends AbstractJacksonHttpMessageConverter {
|
||||
public class JacksonSmileHttpMessageConverter extends AbstractJacksonHttpMessageConverter<SmileMapper> {
|
||||
|
||||
private static final MediaType DEFAULT_SMILE_MIME_TYPES = new MediaType("application", "x-jackson-smile");
|
||||
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ import org.springframework.util.xml.StaxUtils;
|
||||
* @author Sebastien Deleuze
|
||||
* @since 7.0
|
||||
*/
|
||||
public class JacksonXmlHttpMessageConverter extends AbstractJacksonHttpMessageConverter {
|
||||
public class JacksonXmlHttpMessageConverter extends AbstractJacksonHttpMessageConverter<XmlMapper> {
|
||||
|
||||
private static final List<MediaType> problemDetailMediaTypes =
|
||||
Collections.singletonList(MediaType.APPLICATION_PROBLEM_XML);
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ import org.springframework.http.converter.AbstractJacksonHttpMessageConverter;
|
||||
* @author Sebastien Deleuze
|
||||
* @since 7.0
|
||||
*/
|
||||
public class JacksonYamlHttpMessageConverter extends AbstractJacksonHttpMessageConverter {
|
||||
public class JacksonYamlHttpMessageConverter extends AbstractJacksonHttpMessageConverter<YAMLMapper> {
|
||||
|
||||
/**
|
||||
* Construct a new instance with a {@link YAMLMapper} customized with the
|
||||
|
||||
+7
-8
@@ -31,7 +31,6 @@ import reactor.test.StepVerifier;
|
||||
import tools.jackson.core.JsonParser;
|
||||
import tools.jackson.databind.DeserializationContext;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.annotation.JsonDeserialize;
|
||||
import tools.jackson.databind.deser.std.StdDeserializer;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
@@ -101,9 +100,9 @@ class JacksonJsonDecoderTests extends AbstractDecoderTests<JacksonJsonDecoder> {
|
||||
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), halFormsJsonMediaType)).isTrue();
|
||||
assertThat(decoder.canDecode(ResolvableType.forClass(Map.class), MediaType.APPLICATION_JSON)).isTrue();
|
||||
|
||||
decoder.registerObjectMappersForType(Pojo.class, map -> {
|
||||
map.put(halJsonMediaType, new ObjectMapper());
|
||||
map.put(MediaType.APPLICATION_JSON, new ObjectMapper());
|
||||
decoder.registerMappersForType(Pojo.class, map -> {
|
||||
map.put(halJsonMediaType, new JsonMapper());
|
||||
map.put(MediaType.APPLICATION_JSON, new JsonMapper());
|
||||
});
|
||||
|
||||
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), halJsonMediaType)).isTrue();
|
||||
@@ -115,7 +114,7 @@ class JacksonJsonDecoderTests extends AbstractDecoderTests<JacksonJsonDecoder> {
|
||||
@Test // SPR-15866
|
||||
void canDecodeWithProvidedMimeType() {
|
||||
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
|
||||
JacksonJsonDecoder decoder = new JacksonJsonDecoder(new ObjectMapper(), textJavascript);
|
||||
JacksonJsonDecoder decoder = new JacksonJsonDecoder(new JsonMapper(), textJavascript);
|
||||
|
||||
assertThat(decoder.getDecodableMimeTypes()).isEqualTo(Collections.singletonList(textJavascript));
|
||||
}
|
||||
@@ -124,7 +123,7 @@ class JacksonJsonDecoderTests extends AbstractDecoderTests<JacksonJsonDecoder> {
|
||||
@SuppressWarnings("unchecked")
|
||||
void decodableMimeTypesIsImmutable() {
|
||||
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
|
||||
JacksonJsonDecoder decoder = new JacksonJsonDecoder(new ObjectMapper(), textJavascript);
|
||||
JacksonJsonDecoder decoder = new JacksonJsonDecoder(new JsonMapper(), textJavascript);
|
||||
|
||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() ->
|
||||
decoder.getDecodableMimeTypes().add(new MimeType("text", "ecmascript")));
|
||||
@@ -135,8 +134,8 @@ class JacksonJsonDecoderTests extends AbstractDecoderTests<JacksonJsonDecoder> {
|
||||
MimeType mimeType1 = MediaType.parseMediaType("application/hal+json");
|
||||
MimeType mimeType2 = new MimeType("text", "javascript", StandardCharsets.UTF_8);
|
||||
|
||||
JacksonJsonDecoder decoder = new JacksonJsonDecoder(new ObjectMapper(), mimeType2);
|
||||
decoder.registerObjectMappersForType(Pojo.class, map -> map.put(mimeType1, new ObjectMapper()));
|
||||
JacksonJsonDecoder decoder = new JacksonJsonDecoder(new JsonMapper(), mimeType2);
|
||||
decoder.registerMappersForType(Pojo.class, map -> map.put(mimeType1, new JsonMapper()));
|
||||
|
||||
assertThat(decoder.getDecodableMimeTypes(ResolvableType.forClass(Pojo.class)))
|
||||
.containsExactly(mimeType1);
|
||||
|
||||
+3
-4
@@ -28,7 +28,6 @@ import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.SerializationFeature;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
@@ -109,7 +108,7 @@ class JacksonJsonEncoderTests extends AbstractEncoderTests<JacksonJsonEncoder> {
|
||||
@Test // SPR-15866
|
||||
public void canEncodeWithCustomMimeType() {
|
||||
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
|
||||
JacksonJsonEncoder encoder = new JacksonJsonEncoder(new ObjectMapper(), textJavascript);
|
||||
JacksonJsonEncoder encoder = new JacksonJsonEncoder(new JsonMapper(), textJavascript);
|
||||
|
||||
assertThat(encoder.getEncodableMimeTypes()).isEqualTo(Collections.singletonList(textJavascript));
|
||||
}
|
||||
@@ -117,7 +116,7 @@ class JacksonJsonEncoderTests extends AbstractEncoderTests<JacksonJsonEncoder> {
|
||||
@Test
|
||||
void encodableMimeTypesIsImmutable() {
|
||||
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
|
||||
JacksonJsonEncoder encoder = new JacksonJsonEncoder(new ObjectMapper(), textJavascript);
|
||||
JacksonJsonEncoder encoder = new JacksonJsonEncoder(new JsonMapper(), textJavascript);
|
||||
|
||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() ->
|
||||
encoder.getEncodableMimeTypes().add(new MimeType("text", "ecmascript")));
|
||||
@@ -231,7 +230,7 @@ class JacksonJsonEncoderTests extends AbstractEncoderTests<JacksonJsonEncoder> {
|
||||
|
||||
@Test // gh-22771
|
||||
public void encodeWithFlushAfterWriteOff() {
|
||||
ObjectMapper mapper = JsonMapper.builder().configure(SerializationFeature.FLUSH_AFTER_WRITE_VALUE, false).build();
|
||||
JsonMapper mapper = JsonMapper.builder().configure(SerializationFeature.FLUSH_AFTER_WRITE_VALUE, false).build();
|
||||
JacksonJsonEncoder encoder = new JacksonJsonEncoder(mapper);
|
||||
|
||||
Flux<DataBuffer> result = encoder.encode(Flux.just(new Pojo("foo", "bar")), this.bufferFactory,
|
||||
|
||||
+8
-8
@@ -87,9 +87,9 @@ class JacksonJsonHttpMessageConverterTests {
|
||||
assertThat(converter.canRead(MyBean.class, halFormsJsonMediaType)).isTrue();
|
||||
assertThat(converter.canRead(Map.class, MediaType.APPLICATION_JSON)).isTrue();
|
||||
|
||||
converter.registerObjectMappersForType(MyBean.class, map -> {
|
||||
map.put(halJsonMediaType, new ObjectMapper());
|
||||
map.put(MediaType.APPLICATION_JSON, new ObjectMapper());
|
||||
converter.registerMappersForType(MyBean.class, map -> {
|
||||
map.put(halJsonMediaType, new JsonMapper());
|
||||
map.put(MediaType.APPLICATION_JSON, new JsonMapper());
|
||||
});
|
||||
|
||||
assertThat(converter.canRead(MyBean.class, halJsonMediaType)).isTrue();
|
||||
@@ -121,9 +121,9 @@ class JacksonJsonHttpMessageConverterTests {
|
||||
assertThat(converter.getSupportedMediaTypes(MyBean.class)).containsExactly(defaultMediaTypes);
|
||||
|
||||
MediaType halJson = MediaType.parseMediaType("application/hal+json");
|
||||
converter.registerObjectMappersForType(MyBean.class, map -> {
|
||||
map.put(halJson, new ObjectMapper());
|
||||
map.put(MediaType.APPLICATION_JSON, new ObjectMapper());
|
||||
converter.registerMappersForType(MyBean.class, map -> {
|
||||
map.put(halJson, new JsonMapper());
|
||||
map.put(MediaType.APPLICATION_JSON, new JsonMapper());
|
||||
});
|
||||
|
||||
assertThat(converter.getSupportedMediaTypes(MyBean.class)).containsExactly(halJson, MediaType.APPLICATION_JSON);
|
||||
@@ -365,7 +365,7 @@ class JacksonJsonHttpMessageConverterTests {
|
||||
PrettyPrintBean bean = new PrettyPrintBean();
|
||||
bean.setName("Jason");
|
||||
|
||||
ObjectMapper mapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
|
||||
JsonMapper mapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
|
||||
this.converter = new JacksonJsonHttpMessageConverter(mapper);
|
||||
this.converter.write(bean, ResolvableType.forType(PrettyPrintBean.class),
|
||||
MediaType.APPLICATION_JSON, outputMessage, null);
|
||||
@@ -384,7 +384,7 @@ class JacksonJsonHttpMessageConverterTests {
|
||||
PrettyPrintBean bean = new PrettyPrintBean();
|
||||
bean.setName("Jason");
|
||||
|
||||
ObjectMapper mapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
|
||||
JsonMapper mapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
|
||||
this.converter = new JacksonJsonHttpMessageConverter(mapper);
|
||||
this.converter.write(bean, ResolvableType.forType(PrettyPrintBean.class),
|
||||
MediaType.APPLICATION_JSON, outputMessage, null);
|
||||
|
||||
Reference in New Issue
Block a user