spring-integrationspring-integration-http

Error handling issue with http ResponseEntity using ExpressionEvaluatingRequestHandlerAdvice


Continuation of Error handling - no output-channel or replyChannel header available,

I am returning ResponseEntity from the transformer of ExpressionEvaluatingRequestHandlerAdvice failureChannel. when I debug I can see ResponseEntity<Object> response = <409 CONFLICT Conflict,com.practice.integration.commons.error.AdapterErrorResponse@4d5a370b,[]> and its body(AdapterErrorResponse POJO) has HttpStatus status, List<AdapterError> errors which has populated correct value that I want and as per Artem Bilan's suggestion for preserving request message headers I am sending that response as MessageBuilder.withPayload(response).copyHeaders(message.getPayload().getFailedMessage().getHeaders()).build()

and I have also configured output channel on the transformer but it still does not show the above response as a part of http response payload, output channel I have is same as reply channel of the inbound gateway. could you please help here?

and I have one more external call following the above, there also I have used different transformer to handle exception and I am sending similar ResponseEntity from there , it works fine there and send response to the reply channel of the inbound gateway. Only difference is I am not using ExpressionEvaluatingRequestHandlerAdvice for the second outbound gateway.

Do you think I should do something extra with handling response using ExpressionEvaluatingRequestHandlerAdvice or am I missing anything on the first outbound gateway?


Solution

  • You probably didn't do this: ExpressionEvaluatingRequestHandlerAdvice.setTrapException(true);

    Here is a working test, it is not HTTP based, but approach is exactly the same for any inbound request-reply gateway:

    @SpringJUnitConfig
    public class So74658669Tests {
    
        @Autowired
        InputGateway inputGateway;
    
        @Test
        void errorHandlerResultPropagatedBackToGateway() {
            assertThat(this.inputGateway.sendAndReceive("test"))
                    .isEqualTo("Request failed for: test");
        }
    
        @Configuration
        @EnableIntegration
        @Import(InputGateway.class)
        public static class TestConfiguration {
    
            @Bean
            MessageChannel outputChannel() {
                return new DirectChannel();
            }
    
            @ServiceActivator(inputChannel = "inputChannel", outputChannel = "outputChannel", adviceChain = "requestHandlerAdvice")
            String requestAndReply(String payload) {
                throw new RuntimeException("failure");
            }
    
            @Bean
            ExpressionEvaluatingRequestHandlerAdvice requestHandlerAdvice() {
                ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice();
                advice.setFailureChannelName("errorHandlerChannel");
                advice.setTrapException(true);
                return advice;
            }
    
            @Transformer(inputChannel = "errorHandlerChannel", outputChannel = "outputChannel")
            Message<String> errorHandler(Message<MessagingException> errorMessage) {
                return MessageBuilder.withPayload("Request failed for: " + errorMessage.getPayload().getFailedMessage().getPayload())
                        .copyHeaders(errorMessage.getPayload().getFailedMessage().getHeaders())
                        .build();
            }
    
        }
    
        @MessagingGateway
        interface InputGateway {
    
            @Gateway(requestChannel = "inputChannel", replyChannel = "outputChannel")
            String sendAndReceive(String payload);
    
        }
    
    }
    

    By the way there is no need in that outputChannel at all if you don't do any extra work on reply. The framework just find a replyChannel header and sends reply message directly to the input gateway.