MilindaD
MilindaD

Reputation: 7653

Splitter returning empty array list spring integration

We have a case where in our spring integration splitter logic where it could return an empty ArrayList thus providing no data to be routed. How should we handle this scenario and reroute it to a different channel when there is an empty ArrayList returned from the splitter.

UPDATE :

As shown by Artem I have created a custom advice and have got the rerouting to be done successfully however there are still two issues, where the second one describe is the blocker issue listed

The current class that I have is as follows

public class EmptyListRequestHandlerAdvice extends AbstractRequestHandlerAdvice {

    private final MessagingTemplate messagingTemplate = new MessagingTemplate();

    public EmptyListRequestHandlerAdvice(MessageChannel emptyListChannel) {
        this.messagingTemplate.setDefaultChannel(emptyListChannel);
    }

    @Override
    protected Object doInvoke(ExecutionCallback callback, Object target,
            Message<?> message) throws Exception {
        Object result = callback.execute();

        if (result==null) {
            this.messagingTemplate.convertAndSend(new ArrayList<InventoryHotel>());
        }

        return result;
    }

Whenever the splitter returns a new empty array list the result of "callback.execute() is null. However whenever the returned array list from the splitter is not empty the returned result is of type org.springframework.integration.util.FunctionIterator and not a collection type. Any idea on if it is possible to get a collection returned in both cases instead of null or function iterator? Atleast avoid getting a function iterator and get an array list.

Additionally when a valid channel name is set to the constructor and a message is sent through that channel to the transformer method the transformer method is successfully executed however when it returned a value the following error occurs

org.springframework.messaging.MessagingException: org.springframework.messaging.core.DestinationResolutionException: no output-channel or replyChannel header available
    at org.springframework.integration.dispatcher.AbstractDispatcher.wrapExceptionIfNecessary(AbstractDispatcher.java:133)
    at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:120)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:101)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:97)
    at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:255)

Any suggestions on why this occurs and how to resolve it.

Regards, Milinda

Upvotes: 4

Views: 2048

Answers (1)

Artem Bilan
Artem Bilan

Reputation: 121337

Well, you can overcome it with <request-handler-advice-chain> for the <splitter> and of course some custom AbstractRequestHandlerAdvice:

public class EmptyListRequestHandlerAdvice extends AbstractRequestHandlerAdvice {

    private final MessagingTemplate messagingTemplate = new MessagingTemplate();

    public EmptyListRequestHandlerAdvice(MessageChannel emptyListChannel) {
         this.messagingTemplate.setDefaultChannel(emptyListChannel);
    }

    @Override
    protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) throws Exception {
          Collection<?> result = (Collection<?>) callback.execute();
          if (result.isEmpty) {
             this.messagingTemplate.convertAndSend(result);
          }
          return result;
     }

} 

UPDATE

Having that class you can use it like this:

<splitter>
  <request-handler-advice-chain>
      <beans:bean class="com.my.proj.int.EmptyListRequestHandlerAdvice">
          <beans:constructor-arg ref="emptyListChannel"/>
      </beans:bean>
  </request-handler-advice-chain>
</splitter>

<channel id="emptyListChannel"/>

UPDATE2

Any idea on if it is possible to get a collection returned in both cases instead of null or function iterator?

No, it isn't possible. It is an internal logic of the splitter, and of cause its handleRequestMessage produces an Iterator to have a streaming split process gain. It's isn't clear what is the reason for you to have Collection, since splitter is alwasy produces several messages and an iteration logic is hidden from you.

From your first requirement, you asked for the solution to send an empty list to different channel. So, I don't see why the iterator logic should impact you.

no output-channel or replyChannel header available

You really should do this:

this.messagingTemplate.send(MessageBuilder.withPayload(new ArrayList<InventoryHotel>())
      .copyHeaders(message.getHeaders().build());

Having a new message based on that requestMessage you'll copy all its header, so the replyChannel header is there too.

Upvotes: 3

Related Questions