如何将默认 MessageConverter 设置为 JSON 添加了 jackson-dataformat-xml?

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

我有一个可用的 spring 启动应用程序,它使用 JSON 作为交换数据格式。现在我必须添加一项服务,该服务仅在 xml 中发送他们的数据。我将 jackson-dataformat-xml 添加到我的 pom 中,它运行良好。

@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;
    }
}

现在不幸的是,在添加依赖项后,我所有其他 POST 方法默认发送 XML。或者 Content 设置为 application/xml。但我想在这里设置 JSON。

@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);
    //...
    }
}

我没有明确设置 headers,因为有很多 POST 请求,我不想全部更改。有没有办法将 default Content 设置为 JSON?

到目前为止我试过了

  1. 添加拦截器。但有时我需要 XML。
  2. 覆盖内容协商
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.defaultContentType(MediaType.APPLICATION_JSON);
    }
  1. 设置
restTemplate.setMessageConverters(Collections.singletonList(new MappingJackson2HttpMessageConverter()));

并在我想要 XML 的服务中使用 new RestTemplate()

==> 数字 3 确实有效,但感觉有点不对。

我希望在某处设置默认的 Content 类型,以便 JSON 在没有设置的正常情况下使用,而 XML 在我明确设置 Content 到 XML.

感谢您的帮助。

Creating a RestTemplate bean from the auto-configured RestTemplateBuilder bean and using it doesn't manifest the situation. This is a test to demonstrate the situation.

我们最终发现,消息转换器的顺序非常重要。 Jackson 似乎将 XML 消息转换器放在 JSON 消息转换器之前。所以我们将 XML 消息转换移到了最后,它起作用了。

    @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;
}

您可以按照已接受答案的建议更改消息转换器的顺序,并且效果很好。如果请求没有 Content-Type header,Jackson 会选择优先级最高的消息转换器。

因此,如果您不想更改 RestTemplate 的配置,您可以将 Content-Type 设置为 application/json,这将指示 Jackson 使用正确的消息转换器您的要求:

HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.ACCEPT, "application/json");
headers.add(HttpHeaders.CONTENT_TYPE, "application/json");

var httpEntity = new HttpEntity<>(requestBody, headers);
ResponseEntity<String> responseEntity = restTemplate.exchange(
    tenantConfig.getTokenUri(), HttpMethod.POST, httpEntity, String.class);

订单由Spring控制。如果您查看 RestTemplate 的默认构造函数,MessageConverter 将根据直接从上面的静态块确定的布尔值添加到列表中(有一个 Spring 属性 被咨询--spring.xml.ignore——控制是否排除加载所有 XML-related 基础设施)。在安装过程中,列表的顺序似乎没有 modify-able。这看起来确实是一个限制,尽管有一个构造函数接受 MessageConverter 列表并使用它。