spring-bootspring-integrationspring-integration-dslspring-integration-http

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?


Solution

  • 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.