Anton Styopin
Anton Styopin

Reputation: 753

Spring Integration HttpRequestExecutingMessageHandler ContentType Issue

I am facing a problem with Spring Integration. I am trying to execute a rest call via HttpRequestExecutingMessageHandler. My rest endpoint is accepting content-type 'application/json' only.

The problem is that the HttpRequestExecutingMessageHandler is posting with content-type 'text/plain;charset=UTF-8'.

@ServiceActivator(inputChannel = "transformRequestToJsonChannel", 
   outputChannel = "httpRequestOutChannel")
public Message<?> transformRequest(Message<DocumentConverterRequest> 
   message) 
{
  LOG.info("transforming document converter request to json: '{}'",         
  ObjectToJsonTransformer transformer = new ObjectToJsonTransformer();
  transformer.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
  Object payload = transformer.transform(message).getPayload();
  LOG.info("payload: '{}'", payload.toString());
  return MessageBuilder.withPayload(payload).build();
}

@Bean
@ServiceActivator(inputChannel = "httpRequestOutChannel")
public HttpRequestExecutingMessageHandler outbound() {
  HttpRequestExecutingMessageHandler handler = new 
  HttpRequestExecutingMessageHandler(documentConverterRestUrl);
  handler.setHttpMethod(HttpMethod.POST);
  handler.setErrorHandler(httpResponseErrorHandler);
  handler.setExpectedResponseType(String.class);
  handler.setCharset(Charset.defaultCharset().name());
  HeaderMapper<HttpHeaders> mapper = new DefaultHttpHeaderMapper();
  HttpHeaders httpHeaders = new HttpHeaders();
  httpHeaders.add(HttpHeaders.CONTENT_TYPE, 
    MediaType.APPLICATION_JSON_VALUE);
  mapper.toHeaders(httpHeaders);
  handler.setHeaderMapper(mapper);
  handler.setOutputChannel(httpResponseChannel());
  return handler;
}

How can i override the content-type?

Upvotes: 0

Views: 1270

Answers (2)

Anton Styopin
Anton Styopin

Reputation: 753

@Bean
@ServiceActivator(inputChannel = "httpRequestOutChannel")
public HttpRequestExecutingMessageHandler outbound() {
  HttpRequestExecutingMessageHandler handler = Http.outboundGateway(documentConverterRestUrl)
        .httpMethod(HttpMethod.POST)
        .messageConverters(new MappingJackson2HttpMessageConverter())
        .mappedRequestHeaders("Content-Type")
        .get();

        handler.setOutputChannel(httpResponseChannel());
        return handler;
}

I removed my ObjectToJsonTransformer, because the messageConverters(new MappingJackson2HttpMessageConverter()) is doing the stuff.

Also i had to add the content-type to my message header: .setHeaderIfAbsent(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)

Upvotes: 0

Artem Bilan
Artem Bilan

Reputation: 121542

This piece of code does nothing:

  HeaderMapper<HttpHeaders> mapper = new DefaultHttpHeaderMapper();
  HttpHeaders httpHeaders = new HttpHeaders();
  httpHeaders.add(HttpHeaders.CONTENT_TYPE, 
    MediaType.APPLICATION_JSON_VALUE);
  mapper.toHeaders(httpHeaders);

That toHeaders() is called from the HttpRequestExecutingMessageHandler when we receive response. It really useless to use it explicitly in your code, especially in the bean definition phase and when you ignore a result.

You don't need to use an explicit HeaderMapper at all: a default one should be enough for you.

The ObjectToJsonTransformer really maps that setContentType() into a headers of the message it replies:

if (headers.containsKey(MessageHeaders.CONTENT_TYPE)) {
        // override, unless empty
        if (this.contentTypeExplicitlySet && StringUtils.hasLength(this.contentType)) {
            headers.put(MessageHeaders.CONTENT_TYPE, this.contentType);
        }
}
else if (StringUtils.hasLength(this.contentType)) {
        headers.put(MessageHeaders.CONTENT_TYPE, this.contentType);
}

So, there is a proper content type to map. By default HttpRequestExecutingMessageHandler uses:

/**
 * Factory method for creating a basic outbound mapper instance.
 * This will map all standard HTTP request headers when sending an HTTP request,
 * and it will map all standard HTTP response headers when receiving an HTTP response.
 * @return The default outbound mapper.
 */
public static DefaultHttpHeaderMapper outboundMapper() {

With an appropriate set of headers to map to HTTP request and from HTTP response.

The new DefaultHttpHeaderMapper() brings just an empty set of headers to map.

Please, raise an issue to improve JavaDocs and Reference Manual to note that default ctor of that class doesn't bring any headers to map.

Upvotes: 0

Related Questions