Skip to content

Commit 0d16c91

Browse files
committed
MIME types by Class for Encoder, Decoder, HttpMessageReader|Writer
Closes gh-26212
1 parent 7cdaaa2 commit 0d16c91

File tree

14 files changed

+208
-34
lines changed

14 files changed

+208
-34
lines changed

spring-core/src/main/java/org/springframework/core/codec/Decoder.java

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.core.codec;
1818

19+
import java.util.Collections;
1920
import java.util.List;
2021
import java.util.Map;
2122
import java.util.concurrent.CompletableFuture;
@@ -59,7 +60,7 @@ public interface Decoder<T> {
5960
* this type must have been previously passed to the {@link #canDecode}
6061
* method and it must have returned {@code true}.
6162
* @param mimeType the MIME type associated with the input stream (optional)
62-
* @param hints additional information about how to do encode
63+
* @param hints additional information about how to do decode
6364
* @return the output stream with decoded elements
6465
*/
6566
Flux<T> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
@@ -72,7 +73,7 @@ Flux<T> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
7273
* this type must have been previously passed to the {@link #canDecode}
7374
* method and it must have returned {@code true}.
7475
* @param mimeType the MIME type associated with the input stream (optional)
75-
* @param hints additional information about how to do encode
76+
* @param hints additional information about how to do decode
7677
* @return the output stream with the decoded element
7778
*/
7879
Mono<T> decodeToMono(Publisher<DataBuffer> inputStream, ResolvableType elementType,
@@ -85,7 +86,7 @@ Mono<T> decodeToMono(Publisher<DataBuffer> inputStream, ResolvableType elementTy
8586
* @param buffer the {@code DataBuffer} to decode
8687
* @param targetType the expected output type
8788
* @param mimeType the MIME type associated with the data
88-
* @param hints additional information about how to do encode
89+
* @param hints additional information about how to do decode
8990
* @return the decoded value, possibly {@code null}
9091
* @since 5.2
9192
*/
@@ -111,8 +112,27 @@ default T decode(DataBuffer buffer, ResolvableType targetType,
111112
}
112113

113114
/**
114-
* Return the list of MIME types this decoder supports.
115+
* Return the list of MIME types supported by this Decoder. The list may not
116+
* apply to every possible target element type and calls to this method
117+
* should typically be guarded via {@link #canDecode(ResolvableType, MimeType)
118+
* canDecode(elementType, null)}. The list may also exclude MIME types
119+
* supported only for a specific element type. Alternatively, use
120+
* {@link #getDecodableMimeTypes(ResolvableType)} for a more precise list.
121+
* @return the list of supported MIME types
115122
*/
116123
List<MimeType> getDecodableMimeTypes();
117124

125+
/**
126+
* Return the list of MIME types supported by this Decoder for the given type
127+
* of element. This list may differ from {@link #getDecodableMimeTypes()}
128+
* if the Decoder doesn't support the given element type or if it supports
129+
* it only for a subset of MIME types.
130+
* @param targetType the type of element to check for decoding
131+
* @return the list of MIME types supported for the given target type
132+
* @since 5.3.4
133+
*/
134+
default List<MimeType> getDecodableMimeTypes(ResolvableType targetType) {
135+
return (canDecode(targetType, null) ? getDecodableMimeTypes() : Collections.emptyList());
136+
}
137+
118138
}

spring-core/src/main/java/org/springframework/core/codec/Encoder.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.core.codec;
1818

19+
import java.util.Collections;
1920
import java.util.List;
2021
import java.util.Map;
2122

@@ -90,8 +91,27 @@ default DataBuffer encodeValue(T value, DataBufferFactory bufferFactory,
9091
}
9192

9293
/**
93-
* Return the list of mime types this encoder supports.
94+
* Return the list of MIME types supported by this Encoder. The list may not
95+
* apply to every possible target element type and calls to this method should
96+
* typically be guarded via {@link #canEncode(ResolvableType, MimeType)
97+
* canEncode(elementType, null)}. The list may also exclude MIME types
98+
* supported only for a specific element type. Alternatively, use
99+
* {@link #getEncodableMimeTypes(ResolvableType)} for a more precise list.
100+
* @return the list of supported MIME types
94101
*/
95102
List<MimeType> getEncodableMimeTypes();
96103

104+
/**
105+
* Return the list of MIME types supported by this Encoder for the given type
106+
* of element. This list may differ from the {@link #getEncodableMimeTypes()}
107+
* if the Encoder doesn't support the element type or if it supports it only
108+
* for a subset of MIME types.
109+
* @param elementType the type of element to check for encoding
110+
* @return the list of MIME types supported for the given element type
111+
* @since 5.3.4
112+
*/
113+
default List<MimeType> getEncodableMimeTypes(ResolvableType elementType) {
114+
return (canEncode(elementType, null) ? getEncodableMimeTypes() : Collections.emptyList());
115+
}
116+
97117
}

spring-web/src/main/java/org/springframework/http/codec/DecoderHttpMessageReader.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -87,6 +87,10 @@ public List<MediaType> getReadableMediaTypes() {
8787
return this.mediaTypes;
8888
}
8989

90+
@Override
91+
public List<MediaType> getReadableMediaTypes(ResolvableType elementType) {
92+
return MediaType.asMediaTypes(this.decoder.getDecodableMimeTypes(elementType));
93+
}
9094

9195
@Override
9296
public boolean canRead(ResolvableType elementType, @Nullable MediaType mediaType) {

spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -105,6 +105,10 @@ public List<MediaType> getWritableMediaTypes() {
105105
return this.mediaTypes;
106106
}
107107

108+
@Override
109+
public List<MediaType> getWritableMediaTypes(ResolvableType elementType) {
110+
return MediaType.asMediaTypes(getEncoder().getEncodableMimeTypes(elementType));
111+
}
108112

109113
@Override
110114
public boolean canWrite(ResolvableType elementType, @Nullable MediaType mediaType) {

spring-web/src/main/java/org/springframework/http/codec/HttpMessageReader.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.http.codec;
1818

19+
import java.util.Collections;
1920
import java.util.List;
2021
import java.util.Map;
2122

@@ -43,10 +44,29 @@
4344
public interface HttpMessageReader<T> {
4445

4546
/**
46-
* Return the {@link MediaType}'s that this reader supports.
47+
* Return the list of media types supported by this reader. The list may not
48+
* apply to every possible target element type and calls to this method
49+
* should typically be guarded via {@link #canRead(ResolvableType, MediaType)
50+
* canWrite(elementType, null)}. The list may also exclude media types
51+
* supported only for a specific element type. Alternatively, use
52+
* {@link #getReadableMediaTypes(ResolvableType)} for a more precise list.
53+
* @return the general list of supported media types
4754
*/
4855
List<MediaType> getReadableMediaTypes();
4956

57+
/**
58+
* Return the list of media types supported by this Reader for the given type
59+
* of element. This list may differ from {@link #getReadableMediaTypes()}
60+
* if the Reader doesn't support the element type, or if it supports it
61+
* only for a subset of media types.
62+
* @param elementType the type of element to read
63+
* @return the list of media types supported for the given class
64+
* @since 5.3.4
65+
*/
66+
default List<MediaType> getReadableMediaTypes(ResolvableType elementType) {
67+
return (canRead(elementType, null) ? getReadableMediaTypes() : Collections.emptyList());
68+
}
69+
5070
/**
5171
* Whether the given object type is supported by this reader.
5272
* @param elementType the type of object to check
@@ -56,7 +76,7 @@ public interface HttpMessageReader<T> {
5676
boolean canRead(ResolvableType elementType, @Nullable MediaType mediaType);
5777

5878
/**
59-
* Read from the input message and encode to a stream of objects.
79+
* Read from the input message and decode to a stream of objects.
6080
* @param elementType the type of objects in the stream which must have been
6181
* previously checked via {@link #canRead(ResolvableType, MediaType)}
6282
* @param message the message to read from
@@ -66,7 +86,7 @@ public interface HttpMessageReader<T> {
6686
Flux<T> read(ResolvableType elementType, ReactiveHttpInputMessage message, Map<String, Object> hints);
6787

6888
/**
69-
* Read from the input message and encode to a single object.
89+
* Read from the input message and decode to a single object.
7090
* @param elementType the type of objects in the stream which must have been
7191
* previously checked via {@link #canRead(ResolvableType, MediaType)}
7292
* @param message the message to read from

spring-web/src/main/java/org/springframework/http/codec/HttpMessageWriter.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.http.codec;
1818

19+
import java.util.Collections;
1920
import java.util.List;
2021
import java.util.Map;
2122

@@ -43,10 +44,29 @@
4344
public interface HttpMessageWriter<T> {
4445

4546
/**
46-
* Return the {@link MediaType}'s that this writer supports.
47+
* Return the list of media types supported by this Writer. The list may not
48+
* apply to every possible target element type and calls to this method should
49+
* typically be guarded via {@link #canWrite(ResolvableType, MediaType)
50+
* canWrite(elementType, null)}. The list may also exclude media types
51+
* supported only for a specific element type. Alternatively, use
52+
* {@link #getWritableMediaTypes(ResolvableType)} for a more precise list.
53+
* @return the general list of supported media types
4754
*/
4855
List<MediaType> getWritableMediaTypes();
4956

57+
/**
58+
* Return the list of media types supported by this Writer for the given type
59+
* of element. This list may differ from {@link #getWritableMediaTypes()}
60+
* if the Writer doesn't support the element type, or if it supports it
61+
* only for a subset of media types.
62+
* @param elementType the type of element to encode
63+
* @return the list of media types supported for the given class
64+
* @since 5.3.4
65+
*/
66+
default List<MediaType> getWritableMediaTypes(ResolvableType elementType) {
67+
return (canWrite(elementType, null) ? getWritableMediaTypes() : Collections.emptyList());
68+
}
69+
5070
/**
5171
* Whether the given object type is supported by this writer.
5272
* @param elementType the type of object to check

spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Decoder.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,10 @@ public List<MimeType> getDecodableMimeTypes() {
259259
return getMimeTypes();
260260
}
261261

262+
@Override
263+
public List<MimeType> getDecodableMimeTypes(ResolvableType targetType) {
264+
return getMimeTypes(targetType);
265+
}
262266

263267
// Jackson2CodecSupport
264268

spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Encoder.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -357,6 +357,11 @@ public List<MimeType> getEncodableMimeTypes() {
357357
return getMimeTypes();
358358
}
359359

360+
@Override
361+
public List<MimeType> getEncodableMimeTypes(ResolvableType elementType) {
362+
return getMimeTypes(elementType);
363+
}
364+
360365
@Override
361366
public List<MediaType> getStreamingMediaTypes() {
362367
return Collections.unmodifiableList(this.streamingMediaTypes);

spring-web/src/main/java/org/springframework/http/codec/json/Jackson2CodecSupport.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
1818

1919
import java.lang.annotation.Annotation;
2020
import java.lang.reflect.Type;
21+
import java.util.ArrayList;
2122
import java.util.Arrays;
2223
import java.util.Collections;
2324
import java.util.HashMap;
@@ -148,7 +149,7 @@ public Map<MimeType, ObjectMapper> getObjectMappersForType(Class<?> clazz) {
148149
return Collections.emptyMap();
149150
}
150151

151-
private Map<Class<?>, Map<MimeType, ObjectMapper>> getObjectMapperRegistrations() {
152+
protected Map<Class<?>, Map<MimeType, ObjectMapper>> getObjectMapperRegistrations() {
152153
return (this.objectMapperRegistrations != null ? this.objectMapperRegistrations : Collections.emptyMap());
153154
}
154155

@@ -159,6 +160,17 @@ protected List<MimeType> getMimeTypes() {
159160
return this.mimeTypes;
160161
}
161162

163+
protected List<MimeType> getMimeTypes(ResolvableType elementType) {
164+
Class<?> elementClass = elementType.toClass();
165+
List<MimeType> result = null;
166+
for (Map.Entry<Class<?>, Map<MimeType, ObjectMapper>> entry : getObjectMapperRegistrations().entrySet()) {
167+
if (entry.getKey().isAssignableFrom(elementClass)) {
168+
result = (result != null ? result : new ArrayList<>(entry.getValue().size()));
169+
result.addAll(entry.getValue().keySet());
170+
}
171+
}
172+
return (CollectionUtils.isEmpty(result) ? getMimeTypes() : result);
173+
}
162174

163175
protected boolean supportsMimeType(@Nullable MimeType mimeType) {
164176
if (mimeType == null) {

spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyExtractors.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -196,7 +196,7 @@ private static <T, S extends Publisher<T>> S readWithMessageReaders(
196196
.map(readerFunction)
197197
.orElseGet(() -> {
198198
List<MediaType> mediaTypes = context.messageReaders().stream()
199-
.flatMap(reader -> reader.getReadableMediaTypes().stream())
199+
.flatMap(reader -> reader.getReadableMediaTypes(elementType).stream())
200200
.collect(Collectors.toList());
201201
return errorFunction.apply(
202202
new UnsupportedMediaTypeException(contentType, mediaTypes, elementType));

spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyInserters.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -385,7 +385,7 @@ private static UnsupportedMediaTypeException unsupportedError(ResolvableType bod
385385
BodyInserter.Context context, @Nullable MediaType mediaType) {
386386

387387
List<MediaType> supportedMediaTypes = context.messageWriters().stream()
388-
.flatMap(reader -> reader.getWritableMediaTypes().stream())
388+
.flatMap(reader -> reader.getWritableMediaTypes(bodyType).stream())
389389
.collect(Collectors.toList());
390390

391391
return new UnsupportedMediaTypeException(mediaType, supportedMediaTypes, bodyType);

0 commit comments

Comments
 (0)