Sunday, 10 March 2019

Spring Boot 2 and custom JsonSerializer

I was migrating recently to the new Spring Boot version 2. And most annoying thing was that PageImpl (component used for pagination)  changed format. Also I had some issues with Mockito 2, but all of them could be solved read here.

Well I found this article and it all looked easy despite the fact that Spring did not want to use my JsonSerializer. Here how it looks:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.springframework.boot.jackson.JsonComponent;

public class PageImplJacksonSerializer extends JsonSerializer {

    public void serialize(PageImpl page, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeObjectField("content", page.getContent());
        jsonGenerator.writeBooleanField("first", page.isFirst());
        jsonGenerator.writeBooleanField("last", page.isLast());
        jsonGenerator.writeNumberField("totalPages", page.getTotalPages());
        jsonGenerator.writeNumberField("totalElements", page.getTotalElements());
        jsonGenerator.writeNumberField("numberOfElements", page.getNumberOfElements());
        jsonGenerator.writeNumberField("size", page.getSize());
        jsonGenerator.writeNumberField("number", page.getNumber());
        Sort sort = page.getSort();
        for (Sort.Order order : sort) {
            jsonGenerator.writeStringField("property", order.getProperty());
            jsonGenerator.writeStringField("direction", order.getDirection().name());
            jsonGenerator.writeBooleanField("ignoreCase", order.isIgnoreCase());
            jsonGenerator.writeStringField("nullHandling", order.getNullHandling().name());
Next I read Spring docs of how can I customize Serializer here and here They suggested to create jacksonBuilder with your specific module or register JsonComponentModule that will find your serializer that will be used by spring during mapper creation. Unfortunately none of this worked for me:

    public Module jsonComponentModule() {
        return new JsonComponentModule();

And this also didn't work:

    public Jackson2ObjectMapperBuilder jacksonBuilder() {
        JsonComponentModule module  = new JsonComponentModule();
        module.addSerializer(PageImpl.class, new PageImplJacksonSerializer());
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        return builder;
I continued with my last idea, suggested by docs is configuring HttpMessageConverter. And here I figured out that my config extends WebMvcConfigurationSupport to enable MVC and after debugging spring context creation. I found that Spring registers default converters with method addDefaultHttpMessageConverters and following line of code and for some reason it does not register serializer here:

messageConverters.add(new MappingJackson2HttpMessageConverter(;

So here is working solution for me, with configuring default converter created by Spring:

    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter converter = (MappingJackson2HttpMessageConverter)
                        .filter(c -> c instanceof MappingJackson2HttpMessageConverter)
        Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
        JsonComponentModule module  = new JsonComponentModule();
        module.addSerializer(PageImpl.class, new PageImplJacksonSerializer());
        ObjectMapper objectMapper = builder.modules(module).build();


  1. Hi,

    Actually there is a simple way that configure PageImplJacksonSerializer's path for component scanning. JsonComponentModule(org.springframework.boot.jackson) registers json beans which annotated with @JsonComponent.

    public class SerializerConfig {


    1. unfortunately it didn't work for me, spring find it but do not use when i return json from controller