0
votes

i am trying to suppress MessageHandlingException generated from http outbound gateway for non 2XX status codes and gracefully return back the control to the parent flow so that message with original payload is given back on the reply channel as intended in success flow.

original code :

 @Bean
  public IntegrationFlow inquiry() {
    return flow -> flow
    .handle(Http
                .outboundGateway("url", restTemplate)
                .mappedRequestHeaders("*")
                .headerMapper(headerMapper)
                .extractPayload(true)
                .httpMethod(HttpMethod.POST)
                .expectedResponseType(expectedResponseType.class)
            )

i tried with errorHandler on Http, but it gives a handle to the client response and original payload is not part of it.

Tried Expression Advice route as well.

@Bean
  public IntegrationFlow inquiry() {
    return flow -> flow
    .handle(Http
                    .outboundGateway("url", restTemplate)
                    .mappedRequestHeaders("*")
                    .headerMapper(headerMapper)
                    .extractPayload(true)
                    .httpMethod(HttpMethod.POST)
                    .expectedResponseType(expectedResponseType.class)
                , c->c.advice(expresionAdvice())) 

The advice is not returning back the control if there is no success & failure channel, but the intention is return back the control to parent.

Probably the easiest way is to wrap the .handle with try.. catch and catch the MessageHandlingException and propagate it to @ExceptionHandler and transform it.

is there a way can it be done with advice or errorChannel, tried errorChannel on the @MessagingGateway it not getting invoked after a 404 from http outbound gateway.

The above code is part of another flow and am testing this flow independently.

can there be a error channel at the integrationFlow ?

Update 1:

was able to figure out why errorChannel on @MessagingGateway is not getting invoked from the test, it is only getting invoked when the complete flow is called rather than only inquiry() method using DirectChannel.

Now that the errorChannel is working , have set a custom header using the payload state that was before the exception and access it back from the failedMessage Headers.

it is working as expected now and never throws an error back to the response. Feel like it is a work around..

is there a way can this be better handled in advice ?

EDIT 1:

The code is not complete i was trying out to make it work

@Bean
  public Advice expressionAdvice() {
    ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice();
    advice.setOnSuccessExpressionString("payload");
    advice.setOnFailureExpressionString("payload");
    advice.setTrapException(true);
    return advice;
  }

Since i have not specified the channel flow from advice, the flow is nowhere to go, need some thing like .defaultOutputToParentFlow() so that it goes back to the parent flow with the Message.

Answer :

It worked, But the the only catch is, i still need the custom header to get the original payload rather than request failure payload/body for the process to continue.

@Bean
  public Advice expressionAdvice() {
    ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice();
    advice.setOnSuccessExpressionString("payload");
    advice.setOnFailureExpressionString("headers['CUSTOM_KEY']");
    advice.setTrapException(true);
    advice.setReturnFailureExpressionResult(true);
    return advice;
  }

This is what i was looking. May be change the variable name as the advice will return on success as well not just failure cases.

1
Edit the question to show your expresionAdvice() bean.Gary Russell
See my answer about that adviceArtem Bilan

1 Answers

0
votes

You need also to configure on the ExpressionEvaluatingRequestHandlerAdvice this to true:

/**
 * If true, the result of evaluating the onFailureExpression will
 * be returned as the result of AbstractReplyProducingMessageHandler.handleRequestMessage(Message).
 *
 * @param returnFailureExpressionResult true to return the result of the evaluation.
 */
public void setReturnFailureExpressionResult(boolean returnFailureExpressionResult) {
    this.returnFailureExpressionResult = returnFailureExpressionResult;
}