Spring-integration ExpressionEvaluatingRequestHandlerAdvice unable to evaluate the failureExpression

Viewed 157

Following a question I made yesterday, I found some issues with the ExpressionEvaluatingRequestHandlerAdvice because it isn't working as I expected.

I tried the doc example and my expectation were to get two AdviceMessage: one saying "good was successful" and another one saying "bad was bad, with reason..." but when I run the code I get an AdviceMessage and an ErrorMessage.

AdviceMessage [payload=good was successful, headers={id=2eb612ea-d3cd-f853-3295-236505a130f3, timestamp=1611307975199}, inputMessage=GenericMessage [payload=good, headers={id=725e89ea-be09-7534-1b29-5c7412a99a79, timestamp=1611307975196}]]
ErrorMessage [payload=org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice$MessageHandlingExpressionEvaluatingAdviceException: Handler Failed; nested exception is java.lang.IllegalStateException: Could not invoke the method 'public java.lang.Object com.example.demo.EerhaApplication$$Lambda$299/0x00000008401d7040.handle(java.lang.Object,org.springframework.messaging.MessageHeaders)', failedMessage=GenericMessage [payload=bad, headers={id=7639425f-7676-d521-5994-4c74e5b09f4a, timestamp=1611307975200}], headers={id=aaa07286-4bc3-71e5-09fb-6b55a46e0ecf, timestamp=1611307975201}]

Apparently an Exception is always thrown evaluating the failureExpression never getting the desired result.

I'm using Spring Boot 2.4.2 but I've also tried with older versions, having always the same behaviour.

What am I doing wrong?

2 Answers

We need to see your code for this ExpressionEvaluatingRequestHandlerAdvice, but any way, the AdviceMessage is sent only in case of successful evaluation of the onSuccessExpression:

if (evalResult != null && this.successChannel != null) {
    AdviceMessage<?> resultMessage = new AdviceMessage<>(evalResult, message);
    this.messagingTemplate.send(this.successChannel, resultMessage);
}

When you MessageHandler fails (even if onSuccessExpression fails), we go to this branch:

catch (RuntimeException e) {
        Exception actualException = unwrapExceptionIfNecessary(e);
        if (this.onFailureExpression != null) {
            Object evalResult = evaluateFailureExpression(message, actualException);
            if (this.returnFailureExpressionResult) {
                return evalResult;
            }
        }

and there we send an ErrorMessage:

 if (evalResult != null && this.failureChannel != null) {
        MessagingException messagingException =
                new MessageHandlingExpressionEvaluatingAdviceException(message, "Handler Failed",
                        unwrapThrowableIfNecessary(exception), evalResult);
        ErrorMessage errorMessage = new ErrorMessage(messagingException);
        this.messagingTemplate.send(this.failureChannel, errorMessage);
    }

So, what you show is really an expected behavior.

Therefore need to see you config and understand what is your expectation in both cases.

in order to get the the String "bad was bad, with reason..." printed this was my solution:

@Bean
public IntegrationFlow failure() {
  return f -> f.handle(m -> {
    System.out.println(((ExpressionEvaluatingRequestHandlerAdvice.MessageHandlingExpressionEvaluatingAdviceException)m.getPayload()).getEvaluationResult());
  });
}
Related