-
Couldn't load subscription status.
- 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);
}
}