javaspringspring-integration

spring-integration header unwrap issue


I upgraded my spring-integration version 1.5.4 to spring-integration-core 6.3.4 after that I am facing a header issue in routeToRecipients, so whenever I want to reach header info in here the message object converting just an OrderMessage and naturally, I get casting exception. Btw my message broker is rabbitmq I couldnt find any clear explanation in documents or migration document enter link description here

    @Bean
public IntegrationFlow orderRequestFlow() {
    return IntegrationFlow.from(ORDER_CHANNEL)
            .log(Level.TRACE, this.getClass().getName() + ".orderChannel")
            .enrichHeaders(h -> h.header("source", "orderChannel"))
            .<byte[]>handle((message, responseHeaders) -> {
                OrderMessage orderMessage = (OrderMessage) jsonMessageConverter.convert(message);
                Message m = MessageBuilder.withPayload(orderMessage) 
                        .copyHeaders(responseHeaders)
                        .build();

                return m;
            })
            .routeToRecipients(exhaustedRetriesRouter -> exhaustedRetriesRouter
                    .recipient(GenericFlow.EXHAUSTED_CHANNEL,
                            message ->
                            //the message just OrderMessage type, unwrap Message type
                                   ((Message<?>) message).getHeaders().containsKey("x-death")
                                            &&((Long) ((Map<?, ?>) ((List<?>) ((Message<?>) message).getHeaders().get("x-death")).get(0)).get("count") >= 3L))

Solution

  • That's correct. The recipient() contract is:

    public <P> RecipientListRouterSpec recipient(String channelName, GenericSelector<P> selector) {
    

    Where that GenericSelector is instantiated from your lambda. And since Java has generics erasure, there is no way to determine that you would expect the whole Message. And framework assumption that in most cases just a payload is expected in the end-user code.

    For that purpose we have another API:

    public RecipientListRouterSpec recipientMessageSelector(String channelName, MessageSelector selector) {
    

    Where contact of the MessageSelector is :

    boolean accept(Message<?> message);
    

    So, no any generics, not erasure and the framework knows that the whole Message is expected in the target lambda.