- Notifications
You must be signed in to change notification settings - Fork 38.8k
Description
WebFlux 7.0.0-M9: AbstractJacksonEncoder
considers the FILTER_PROVIDER_HINT
only when going through encodeValue()
:
spring-framework/spring-web/src/main/java/org/springframework/http/codec/AbstractJacksonEncoder.java
Lines 224 to 227 in 04492c3
if (hints != null) { | |
jsonView = (Class<?>) hints.get(JSON_VIEW_HINT); | |
filters = (FilterProvider) hints.get(FILTER_PROVIDER_HINT); | |
} |
however when encoding a
Flux<T>
to a non-streaming media type, the hint is ignored. The filter hint should probably be checked here:
spring-framework/spring-web/src/main/java/org/springframework/http/codec/AbstractJacksonEncoder.java
Lines 322 to 334 in 04492c3
private ObjectWriter createObjectWriter( | |
T mapper, ResolvableType valueType, @Nullable MimeType mimeType, | |
@Nullable Class<?> jsonView, @Nullable Map<String, Object> hints) { | |
JavaType javaType = getJavaType(valueType.getType(), null); | |
if (jsonView == null && hints != null) { | |
jsonView = (Class<?>) hints.get(JacksonCodecSupport.JSON_VIEW_HINT); | |
} | |
ObjectWriter writer = (jsonView != null ? mapper.writerWithView(jsonView) : mapper.writer()); | |
if (javaType.isContainerType()) { | |
writer = writer.forType(javaType); | |
} | |
return customizeWriter(writer, mimeType, valueType, hints); |
Context: I was using MappingJacksonValue
extensively to programmatically add Jackson filters to my responses and am replacing it now with using hints, where I noticed that they are not used for Flux<T>
body types.
Side note: Some guidance on how to actually provide hints would be helpful. The only proper, user-facing API I found was the ServerResponse
builder for functional endpoints. But I haven't found anything on how to provide hints for encoding client requests (WebClient
) or responses returned from @RequestMapping
controller methods.
My current solution is to replace the default JacksonJsonEncoder
with a custom one:
class MyCustomEncoder extends JacksonJsonEncoder { MyCustomEncoder(JsonMapper jsonMapper) { super(jsonMapper); } @Override public Flux<DataBuffer> encode(Publisher<?> inputStream, DataBufferFactory bufferFactory, ResolvableType elementType, MimeType mimeType, Map<String, Object> hints) { return Flux.deferContextual(reactorContext -> { FilterProvider myFilter = ...; // Create configured FilterProvider from reactorContext Map<String, Object> hintsToUse = Hints.merge(hints, JacksonCodecSupport.FILTER_PROVIDER_HINT, myFilter); return super.encode(inputStream, bufferFactory, elementType, mimeType, hintsToUse); }); } @Override public DataBuffer encodeValue(Object value, DataBufferFactory bufferFactory, ResolvableType valueType, MimeType mimeType, Map<String, Object> hints) { ContextView reactorContext = Context.empty(); if (hints != null) { // thank you for putting the context in here 🙏 reactorContext = (ContextView) hints.get(ContextView.class.getName(), Context.empty()); } FilterProvider myFilter = ...; // Create configured FilterProvider from reactorContext Map<String, Object> hintsToUse = Hints.merge(hints, JacksonCodecSupport.FILTER_PROVIDER_HINT, myFilter); return super.encodeValue(value, bufferFactory, valueType, mimeType, hintsToUse); } }