-1

I am attempting to add a custom HttpMessageConverter<T> to my (Spring-powered) REST API.

@Configuration
public class SpringWebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new BodyPrinterInterceptor());
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        final List<HttpMessageConverter> injectedConverters = new ArrayList<>();
        final SimpleModule module = new SimpleModule("module", new Version(1, 0, 0, null, null, null))
                .addSerializer(LocalDate.class, new LocalDateSerializer())
                .addDeserializer(LocalDate.class, new LocalDateDeserializer())
                .addSerializer(Type2_Numbers.class, new Type2_Numbers_Serializer())
                .addDeserializer(Type2_Numbers.class, new Type2_Numbers_Deserializer());

        final ObjectMapper objectMapper = new ObjectMapper()
                .enable(SerializationFeature.INDENT_OUTPUT)
                .registerModule(module);
        final MappingJackson2HttpMessageConverter converter1 = new MappingJackson2HttpMessageConverter();
        converter1.setObjectMapper(objectMapper);
        injectedConverters.add(converter1);

        final XmlMapper xmlMapper = new XmlMapper();
        xmlMapper.registerModule(module);
        xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);
        final Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml();
        final MappingJackson2XmlHttpMessageConverter converter2 = new MappingJackson2XmlHttpMessageConverter(builder.build());
        converter2.setObjectMapper(xmlMapper);
        injectedConverters.add(converter2);

        for (HttpMessageConverter injectedConverter : injectedConverters) {
            converters.add(injectedConverter);
        }
    }
}

It seems like the added converters are not working. (Serializers & Deserializers are not being called)

Question How do i correctly add the HttpMessageConverters?

zessi
  • 13
  • 1
  • 6

3 Answers3

1

I believe you forgot to call super.configureMessageConverters(converters) at the end of your function.

Mạnh Quyết Nguyễn
  • 17,677
  • 1
  • 23
  • 51
0

Cause

The problem that caused the issue in my case was that adding a custom HttpMessageConverter of a type that already exists in the provided list of HttpMessageConverters will not result to adding the new HttpMessageConverter nor updating the existing HttpMessageConverter of the same type.

Solution

The problem was solved by removing the existing HttpMessageConverter object from the list first if it shares the same type of the new custom HttpMessageConverter object that is intended to be added. Then adding the new custom HttpMessageConverter.

Implementing the Solution

Utils.java

public class Utils {
    public static void injectConverter(HttpMessageConverter converterToInject, List<HttpMessageConverter<?>> convertersList) {
        convertersList.removeIf(new Predicate<HttpMessageConverter<?>>() {
            @Override
            public boolean test(HttpMessageConverter<?> httpMessageConverter) {
                return converterToInject.getClass() == httpMessageConverter.getClass();
            }
        });
        convertersList.add(converterToInject);
    }
}

SpringWebConfig.java

@Configuration
public class SpringWebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new BodyPrinterInterceptor());
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        final List<HttpMessageConverter> injectedConverters = new ArrayList<>();
        final SimpleModule module = new SimpleModule("module", new Version(1, 0, 0, null, null, null))
                .addSerializer(LocalDate.class, new LocalDateSerializer())
                .addDeserializer(LocalDate.class, new LocalDateDeserializer())
                .addSerializer(Type2_Numbers.class, new Type2_Numbers_Serializer())
                .addDeserializer(Type2_Numbers.class, new Type2_Numbers_Deserializer());

        final ObjectMapper objectMapper = new ObjectMapper()
                .enable(SerializationFeature.INDENT_OUTPUT)
                .registerModule(module);
        final MappingJackson2HttpMessageConverter converter1 = new MappingJackson2HttpMessageConverter();
        converter1.setObjectMapper(objectMapper);
        injectedConverters.add(converter1);

        final XmlMapper xmlMapper = new XmlMapper();
        xmlMapper.registerModule(module);
        xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);
        final Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml();
        final MappingJackson2XmlHttpMessageConverter converter2 = new MappingJackson2XmlHttpMessageConverter(builder.build());
        converter2.setObjectMapper(xmlMapper);
        injectedConverters.add(converter2);

        for (HttpMessageConverter injectedConverter : injectedConverters) {
            Utils.injectConverter(injectedConverter, converters);
        }

    }
}
zessi
  • 13
  • 1
  • 6
  • I felt the need to ask an answer that question. because this particular issue costed me a lot of time and hair! – zessi May 20 '18 at 07:07
0

Suggest to use the following

@Bean
public HttpMessageConverters additionalConverters() {
    return new HttpMessageConverters(new YourCustomHttpMsgConverter());
}

Then extend YourCustomHttpMsgConverter Class with GenericHttpMessageConverter

Further write your implementation for the override methods canRead, read, canWrite, write, canRead, canWrite, getSupportedMediaTypes

Prakash Ayappan
  • 455
  • 2
  • 8