xpathspring-integrationheader-enricher

Spring Integration XPathMessageSplitter + HeadEnricher


I am currently using Spring-Integration with JavaConfig and using IntegrationFlows. I am reading in a xml-file which looks like:

<?xml version="1.0" encoding="utf-8"?>
<languages>
    <language name='de'>
        <translations>
            <translation key='Aktien' value='Aktien'/>
            <translation key='Andere' value='Andere'/>
        </translation>
    </language>
    <language name='en'>
        <translations>
            <translation key='Aktien' value='Stock'/>
            <translation key='Andere' value='Others'/>
        </translation>
    </language>
</languages>

My Configuration currently looks like:

@Bean
public IntegrationFlow translationFileReadingFlow() throws IOException {
    return IntegrationFlows
            .from(pollableFileSource(), e -> e.poller(Pollers.fixedDelay(MAX_VALUE)))
            .split(translationFileSplitter())
            .channel("processFileChannel")
            .logAndReply();
}

@Bean
@SubscribeMapping(value = "processFileChannel")
public IntegrationFlow applicationShutDown() {
    return IntegrationFlows
            .from("processFileChannel")
            .resequence()
            .handle(new ShutdownService())
            .get();
}

private AbstractMessageSplitter translationFileSplitter() {
    XPathMessageSplitter splitter = new XPathMessageSplitter("/languages/*");
    return splitter; 
}

I would like to split the xml by language (what works so far), BUT I would like to add also the information of the languages into the header of the message. The information are in the xml <language name='de'>. Can I solve it with the XPathMessageSplitter directly or do I need the XPathHeaderEnricher, if yes how would it work?

Thank you in advance


Solution

  • Not to the subject:

    I'm not sure that:

    @Bean
    @SubscribeMapping(value = "processFileChannel")
    public IntegrationFlow applicationShutDown() {
    

    Is correct code. The @SubscribeMapping is for a POJO-based method mapping. You definitely can't map an IntegrationFlow. If you still need to call a flow from such a @SubscribeMapping, you need to consider to introduce a @MessagingGateway interface for starting the flow and calling from that POJO-method.

    You indeed cannot add headers via splitter. It is just not its responsibility.

    If you need to populate a header from an XML in the payload, you definitely need to take a look into XPathHeaderEnricher. In your case it could be like this:

    @Bean
    public XPathHeaderEnricher xPathHeaderEnricher() {
        Map<String, XPathExpressionEvaluatingHeaderValueMessageProcessor> expressionMap =
                Collections.singletonMap("language",
                        new XPathExpressionEvaluatingHeaderValueMessageProcessor("/language/@name"));
        return new XPathHeaderEnricher(expressionMap);
    }
    

    and use after that mentioned .split():

    .split(translationFileSplitter())
    .handle(xPathHeaderEnricher())
    

    There is another way via SpEL, though: https://docs.spring.io/spring-integration/docs/5.2.0.RELEASE/reference/html/spel.html#spel-functions

    .enrichHeaders((headers) -> 
                 headers.headerExpression("language", "#xpath(payload, '/language/@name')"))