1
votes

I am using Spring Integration Filter to enforce some validation logic on incoming message. The result of this validation needs to be sent back to Messaging Gateway caller in order to inform what exactly is wrong with the request.

So far I have explored two options:

  1. throwExceptionOnRejection = "true" in Filter annotation

This throws an exception back to the caller but its content is very generic and I cannot find a way to customize it:

detailMessage = "message has been rejected in filter: bean 'validationFilter.requestValidation.filter.handler' for component 'validationFilter.requestValidation.filter'"

Is it possible to customize thrown Exception to include the business reason behind it?

Configuration

Gateway

@MessagingGateway( name="processApiGateway", defaultRequestChannel = "inboundGatewayChannel")
public interface ProcessApiGateway {

    @Gateway
    Response getTransactions(Message<ServiceRequest> payload);

}

Filter

 @Filter(inputChannel="inboundGatewayChannel", throwExceptionOnRejection = "true")
    public boolean requestValidation(Message<ServiceRequest> message) {
        try {
            LocalDate fromDate = LocalDate.parse(message.getPayload().getFromDate());
            LocalDate toDate = LocalDate.parse(message.getPayload().getToDate());
            return (Period.between(fromDate, toDate)).getMonths() <= 1;
        }
        catch (DateTimeParseException ex) {
            return false;
        }
    }

Channel

 @Bean
    public MessageChannel inboundGatewayChannel(@Qualifier("taskExecutor")TaskExecutor taskExecutor) {
        return new ExecutorChannel(taskExecutor);
    
  1. Discard channel usage

This works well, but it feels like that exactly the same validation logic needs to be invoked twice. First time within a Filter method itself to determine if the message needs to be discarded and then the second time within Service Activator in order to process discarded message and understand what it's wrong with it so that appropriate reply can be generated to caller (as far I understand discarded message cannot be modified prior returning it from Filter).

Configuration

Filter

 @Filter(inputChannel="inboundGatewayChannel", discardChannel = "filterDiscardChannel")
    public boolean requestValidation(Message<ServiceRequest> message) {
        try {
            LocalDate fromDate = LocalDate.parse(message.getPayload().getFromDate());
            LocalDate toDate = LocalDate.parse(message.getPayload().getToDate());
            return (Period.between(fromDate, toDate)).getMonths() <= 1;
        }
        catch (DateTimeParseException ex) {
            return false;
        }
    }

Service Activator

 @Service
public class ValidationServiceActivator {

    @ServiceActivator(inputChannel = "filterDiscardChannel")
    public Response handleDiscardMessage(Message<ServiceRequest> message) {
        //the same logic to validate discarded message
    }

}

Discard Channel

@Bean public MessageChannel filterDiscardChannel() { return new PublishSubscribeChannel(); }

Question

What is the best approach to reject incoming message based on set of business rules and notify the caller about specific reason behind it?

1
Exception is raised when filter returns false, it's the same as following one: org.springframework.integration.MessageRejectedException: message has been rejected in filter: bean 'validationFilter.requestValidation.filter.handler' for component 'validationFilter.requestValidation.filter', failedMessage=GenericMessage [....]Dmytro

1 Answers

2
votes

If you would like to send some custom response back, not an exception, then I would suggest to go just plain @ServiceActivator, do the validation logic inside that method and return this or that reply. No need in filter in this case.

It looks like even with a discardChannel it is still not enough for you to determine the problem...