Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set default MessageConverter to JSON with jackson-dataformat-xml added?

I have a working spring boot application that uses JSON as exchange data format. Now I had to add a service that sends their data only in xml. I added jackson-dataformat-xml to my pom and it worked perfectly.

@Service
public class TemplateService {

    private final RestTemplate restTemplate;
    private final String serviceUri;

    public TemplateService (RestTemplate restTemplate, @Value("${service.url_templates}") String serviceUri) {
        this.restTemplate = restTemplate;
        this.serviceUri = serviceUri;
    }

    public boolean createTemplate(Template template) {
        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_XML));
        headers.setContentType(MediaType.APPLICATION_XML);
        HttpEntity entity = new HttpEntity<>(template, headers);
        ResponseEntity<Template> response = restTemplate.exchange(serviceUri, HttpMethod.POST, entity, Template.class);
        if (response.getStatusCode().is2xxSuccessful()) {
            // do some stuff
            return true;
        }
        return false;
    }
}

Now unfortunately after adding the dependency all my other POST methods send XML by default. Or the Content is set to application/xml.But I'd like to have JSON here.

@Service
public class SomeOtherService{

    private final RestTemplate restTemplate;
    private final String anotherUri;

    public SomeOtherService(RestTemplate restTemplate, @Value("${anotherUri.url}") String anotherUri) {
        this.restTemplate = restTemplate;
        this.anotherUri = anotherUri;
    }

    public ComponentEntity doSomething(String projectId, MyNewComponent newComponent) {
        ResponseEntity<MyNewComponent> result = this.restTemplate.exchange(anotherUri ,HttpMethod.POST, new HttpEntity<>(newComponent), MyNewComponent.class);
    //...
    }
}

I did not set the headers explicitly as there are lots of POST requests and I don't want to alter them all. Is there a way to set the default Content to JSON?

So far I tried

  1. adding an interceptor. But sometimes I need to have XML.
  2. Overriding content negotiation
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.defaultContentType(MediaType.APPLICATION_JSON);
    }
  1. setting
restTemplate.setMessageConverters(Collections.singletonList(new MappingJackson2HttpMessageConverter()));

and using a new RestTemplate() in the service where I want to have XML.

==> Number 3 actually works, but feels kind of wrong.

I was expecting to set the default Content type somewhere so that JSON is used in normal cases where nothing is set and XML where I explicitly set the Content to XML.

Thanks for any help.

like image 613
Cliff Pereira Avatar asked Aug 29 '19 08:08

Cliff Pereira


1 Answers

What we ultimately found out, is that the the order of the message converters is highly important. Jackson seems to place the XML message converter before the JSON message converter. So we moved the XML message convert to the end and it worked.

    @Bean
    RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    // move XML converter to the end of list
    List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
    for (int i = 0; i < messageConverters.size() -1 ; i++) {
        if (messageConverters.get(i) instanceof MappingJackson2XmlHttpMessageConverter) {
            Collections.swap(messageConverters, i,messageConverters.size() - 1);
        }
    }

    restTemplate.setMessageConverters(messageConverters);

    // add interceptors if necessary
    restTemplate.setInterceptors(Collections.singletonList(catalogInterceptior()));
    return restTemplate;
}
like image 81
Cliff Pereira Avatar answered Oct 17 '22 21:10

Cliff Pereira