MVC
org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter#writeInternal
WebFlux
org.springframework.http.codec.json.AbstractJackson2Decoder org.springframework.http.codec.json.AbstractJackson2Encoder
Support custom build JsonGenerator in encoder and JsonParser in decoder.
Comment From: sdeleuze
Could you please elaborate a bit to allow us to understand what you mean? I mean objectMapper.getFactory().createGenerator(outputStream, encoding)
is used in both AbstractJackson2HttpMessageConverter
and AbstractJackson2Encoder
and WebFlux has separated encoder/decoder et different API due to Reactive requirements on purpose, so I am not sure to understand your ask.
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: spring-projects-issues
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.
Comment From: honhimW
@sdeleuze
Could you please elaborate a bit to allow us to understand what you mean? I mean
objectMapper.getFactory().createGenerator(outputStream, encoding)
is used in bothAbstractJackson2HttpMessageConverter
andAbstractJackson2Encoder
and WebFlux has separated encoder/decoder et different API due to Reactive requirements on purpose, so I am not sure to understand your ask.
I apologize for not seeing your reply in time.
In some cases, I need to perform some custom operations during JSON serialization and deserialization, such as: filtering fields, field name remapping, value remapping, and so on. These functions can usually be implemented by overriding the methods of com.fasterxml.jackson.core.JsonGenerator (the override is done by delegating to com.fasterxml.jackson.core.util.JsonGeneratorDelegate/com.fasterxml.jackson.core.util.JsonParserDelegate).
“However, the current org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter (MVC) and org.springframework.http.codec.json.AbstractJackson2Encoder (Webflux) do not provide a corresponding way to override the creation process of JsonGenerator during serialization. Therefore, the aforementioned functions cannot be implemented (unless I copy the entire method content and modify it, but this is not elegant).
JsonGenerator generator = mapper.getFactory().createGenerator(byteBuilder, encoding);
SequenceWriter sequenceWriter = writer.writeValues(generator);
//
try (JsonGenerator generator = mapper.getFactory().createGenerator(byteBuilder, encoding)) {
//
}
So, I hope there could be similar methods that can support re-referencing new JsonGeneratorDelegate/JsonParserDelegate, such as providing the following methods:
@Nonnull
protected JsonGenerator delegateGenerator(@Nonnull JsonGenerator generator) {
return generator;
}
@Nonnull
protected JsonParser delegateParser(@Nonnull JsonParser parser) {
return parser;
}
public Flux<DataBuffer> encode(xxxx) {
// ...
JsonGenerator generator = mapper.getFactory().createGenerator(byteBuilder, encoding);
generator = decorateGenerator(generator);
// ...
}
Comment From: sdeleuze
@honhimW JsonGenerator
and JsonParser
level customizations are very low level, I am not sure we should add generic capabilities to customize them. Could you please share more about the use cases you have and why they can't be achieved via Jackson2ObjectMapperBuilder
for example?
Comment From: honhimW
I can certainly provide some use cases. Currently, the features I have implemented based on JsonGenerator mainly include: field filtering, variable name conversion, and i18n. As for why Jackson2ObjectMapperBuilder
cannot be used, it's because the scope of the above features is usually not global, but only effective in specific situations for specific requests.
- Field Filtering: You might be familiar with the use of
@JsonView
. It provides a view function based on predefined annotations, but I need more than that. I hope that the interface provided to external users can declaratively represent the fields they need or exclude the fields they don't. This can save bandwidth and simplify response content. The specific effect is as follows:
```http GET /example HTTP/1.1 fetch-only-include: /data/*/id
Response
{ "data": [ {"id": "1"}, {"id": "2"}, ... ] } ```
```http GET /example HTTP/1.1 fetch-non-exclude: /data/*/id
Response
{ "code": "xxx", "message": "hello" "data": [ {"content": "hello", ...}, {"content": "world", ...}, ... ] } ```
- Variable Name Conversion: In Java development, the naming convention for variable names is usually in
LOWER_CAMEL
format, while in other languages they might prefer to useLOWER_UNDERSCORE
format (such as: cpp/rust/php). When they use my interface, they can declare their preferred naming style for conversion (no need to provide multiple ObjectMappers or even multiple code implementations for this). The specific effect is as follows:
```http GET /example HTTP/1.1 favor-naming-style: LOWER_UNDERSCORE
Response
{ "first_name": "hello world" # LOWER_UNDERSCORE }
{ "firstName": "hello world" # LOWER_CAMEL } ```
- i18n: Simply put, when a field value meets a specific rule,
MessageResource
will be used to implement content replacement. The specific effect is as follows:
```http GET /example HTTP/1.1 lang: en-US
# Java Object { "message": "${say.hello}" }
# Response { "message": "hello world!" # en-US }
{ "message": "你好!" # zh-CN } ```
Comment From: sdeleuze
Thanks for sharing your use case. Let's see if other Spring developers comment here to ask such refinement and communicate a common need that should deserve builtin support.