Issue
We have a usecase where the JSON returned by the endpoint has to be serialized differently based on the endpoint. Is it possible to register two separate ObjectMapper beans and specify which one to use for a specific controller? For example, if I define a custom objectmapper as shown below, can I ask Spring Boot to use this mapper to serialize only the return objects from ControllerTwo but use the default/Primary objectmapper for serializing objects returned from ContorllerOne?
@Bean
@Primary
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper mapper = builder.build();
return mapper;
}
@Bean
public ObjectMapper objectMapperCustom(Jackson2ObjectMapperBuilder builder) {
ObjectMapper mapper = builder.build();
//customize mapper
return mapper;
}
@RestController
public class ControllerOne {
@GetMapping("/personNew/{id}")
public Person getMyClass() {
}
}
@RestController
public class ControllerTwo {
@GetMapping("/personOld/{id}")
public Person getMyClass() {
}
}
Solution
As of 2021 unanswered means it is still not (easy) possible to use an alternative ObjectMapper for the same media/object/response type. I.e.
No, it is not (easy) possible to:
... register Controller specific ObjectMapper in SpringBoot
(..not without "re-implementing" half of spring-web).
But what is (easy) possible:
Is to register custom ObjectMapper
per java- and media type (combinations! + wildcards for the media types)! (additionally to the spring-configured "default object mapper")
With:
//no bean
private ObjectMapper fooMapper() {
return new ObjectMapper()
.configure(SerializationFeature.WRAP_ROOT_VALUE, true)
.configure(SerializationFeature.INDENT_OUTPUT, false)
.setDateFormat(new SimpleDateFormat("dd.MM.yyyy hh:mm:ss"));
}
//no bean
private ObjectMapper barMapper() {
return new ObjectMapper()
.configure(SerializationFeature.WRAP_ROOT_VALUE, true)
.configure(SerializationFeature.INDENT_OUTPUT, false)
.setDateFormat(new SimpleDateFormat("MM/dd/yyyy K:mm:ss a"));
}
we can do:
@Bean //overwrites the autoconfigured
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(
@Autowired ObjectMapper objectMapper // auto- and property configured, when no (alternative) ObjectMapper bean is defined.
) {
MappingJackson2HttpMessageConverter bean = new MappingJackson2HttpMessageConverter();
// set "the default":
bean.setObjectMapper(objectMapper);
// register custom:
bean.registerObjectMappersForType(Foo.class, m -> { //!!
m.put(MediaType.APPLICATION_JSON, fooMapper());
// ...
});
bean.registerObjectMappersForType(Bar.class, m -> {
m.put(MediaType.APPLICATION_JSON, barMapper());
});
return bean;
}
The trick here is not to let spring (directly) manage the object mappers, but to register "plain ones", since all the "spring.jackson.*
magic" will be skipped, once an ObjectMapper bean is present.
To achieve custom "views" of (e.g.) Person
, spring introduced (2014) JSON Views.
Answered By - xerx593
Answer Checked By - Gilberto Lyons (JavaFixing Admin)