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() {
}
}
Yes, that is safe and recommended.
ObjectMapper class can be reused and we can initialize it once as Singleton object. There are so many overloaded versions of readValue() and writeValue() methods to work with byte array, File, input/output stream and Reader/Writer objects.
Interface ObjectMapperAn object mapper is used to serialize and deserialize a Java object to and from a String, byte[] or InputStream. REST Assured provides mappers for XML and JSON out of the box (see ObjectMapperType ) but you can implement this interface to roll your own mapper implementations for custom formats.
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.
registerObjectMappersForType
- javadoc
A complete sample@github.
To achieve custom "views" of (e.g.) Person
, spring introduced (2014) JSON Views.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With