StompHeaderAccessor extends NativeMessageHeaderAccessor which seems to be where the non-stomp headers live, except they are all stored in a single header called nativeHeaders - which itself is a map.
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public GenericMessage<Greeting> greeting(HelloMessage message) throws Exception {
Map<String, List<String>> nativeHeaders = new HashMap<>();
nativeHeaders.put("hello", Collections.singletonList("world"));
Map<String,Object> headers = new HashMap<>();
headers.put(NativeMessageHeaderAccessor.NATIVE_HEADERS, nativeHeaders);
return new GenericMessage<Greeting>(new Greeting("Hello, " + message.getName() + "!"), headers);
}
A simple interceptor server-side to wrap your custom headers to the nativeHeaders header should be enough to expose them client-side where they would be available as a map message.headers.nativeHeaders. Simmilarly, you could write a client-side interceptor to move the nativeHeaders into the regular headers - so before your client is aware of the message, all the expected headers are simply in the message.headers.