Skip to content

AbstractJacksonEncoder ignores FILTER_PROVIDER_HINT when encoding Flux<T> #35575

@kzander91

Description

@kzander91

WebFlux 7.0.0-M9: AbstractJacksonEncoder considers the FILTER_PROVIDER_HINT only when going through encodeValue():

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:

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); } }

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)type: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions