Search code examples
spring-integrationspring-websocket

Best way to automatically add stomp native headers to headers


Our javascript websocket clients adds "custom" headers to all STOMP messages.
My project handles websocket endpoints using spring-websocket @Controller.

@MessageMapping(value = "/mymessages")
public void save(@Payload ToBeSaved payload, @Headers MessageHeaders headers) {
    service.save(toMsg(payload, headers));
}  

protected <P> Message<P> toMsg(P payload, MessageHeaders headers) {
    return MessageBuilder.createMessage(payload, headers);
}

The controller modifies the payload and then passes the new payload and original websocket headers (including the custom ones) to a spring-integration @MessagingGateway.

The underlying IntegrationFlow tries to access the "custom" headers by accessing the message headers with the SPLExpression headers['custom'].
Unfortunately headers['custom'] is always null because custom is actually contained in the nativeHeaders.

I haven't found a way to tell IntegrationFlow to look into nativeHeaders.

Is there a way in spring-websocket to copy all native headers as normal headers ?

Thanks in advance


Solution

  • The spring-websocket can do nothing for your on the matter. It isn't its responsibility.

    If you would really like to have access to something in the nativeHeaders, you should do that manually.

    For your particular case that SpEL may look like:

    headers['nativeHeaders']['custom']
    

    Because nativeHeaders is a Map as well.

    From other side you can use <header-enricher> in your down stream flow to pop all those nativeHeaders to top level.

    And one more point: since Spring Integration 4.2 we provide native support for STOMP adapters. And there is a StompHeaderMapper which does exactly what you want and the code there looks like:

     else if (StompHeaderAccessor.NATIVE_HEADERS.equals(name)) {
                MultiValueMap<String, String> multiValueMap =
                        headers.get(StompHeaderAccessor.NATIVE_HEADERS, MultiValueMap.class);
                for (Map.Entry<String, List<String>> entry1 : multiValueMap.entrySet()) {
                    name = entry1.getKey();
                    if (shouldMapHeader(name, this.outboundHeaderNames)) {
                        String value = entry1.getValue().get(0);
                        if (StringUtils.hasText(value)) {
                            setStompHeader(target, name, value);
                        }
                    }
                }
            }