Reputation: 7653
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
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