0

I have a Spring App working with websocket

I can do the connection and send messages etc.

The @Controller is:

    @MessageMapping("/ws/notification")
    @SendTo("/topic/springframework.topic.websocket.reply")
    public NotificationReply handleNotification(Notification notification) {
     ...
    }

It works fine. Observe the parameter type, Notification, it is a custom object.

Now because audit purposes I have the following:

@Component
public class MessageChannelInterceptorAdapter extends ChannelInterceptorAdapter {

    @Override
    public void postSend(Message<?> message, MessageChannel channel, boolean sent) {

        StompHeaderAccessor stompHeaderAccessor = StompHeaderAccessor.wrap(message);

           ....

        switch(stompHeaderAccessor.getCommand()) {
            case CONNECT:
                logger.info("postSend ...");
                logger.info("STOMP Connect");
                break;
            ...
            case SEND:
                logger.info("postSend ...");
                logger.info("STOMP Send");
                printDetails(message, stompHeaderAccessor);
                break;

        ...
    } 


    private void printDetails(Message<?> message, StompHeaderAccessor stompHeaderAccessor) {
        logger.info("   {}", message.toString());
        logger.info("       Payload: {}", message.getPayload());
        logger.info("       Payload (String): {}", message.getPayload().toString());
        logger.info("           Payload (Class): {}", message.getPayload().getClass());

        if(stompHeaderAccessor.getDestination()!=null && stompHeaderAccessor.getDestination().equals("/app/ws/notification")) {
            logger.info("Aprrrr");
            Notification notification = (Notification) message.getPayload();
            logger.info("{}", notification);
        }

I get:

ERROR o.s.w.s.m.StompSubProtocolHandler - 
Failed to send client message to application via MessageChannel in session 555qe12a. 
Sending STOMP ERROR to client. 
org.springframework.messaging.MessageDeliveryException: 
Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]; 
nested exception is java.lang.ClassCastException: 
[B cannot be cast to com.manuel.jordan.websocket.message.Notification

I understand that [B is a byte[].

Thus exists an easy way with the current Spring Framework API to do a cast for the Message<?> payload to a specific POJO?.

Remember to be applied within the class that it is extending from ChannelInterceptorAdapter

Manuel Jordan
  • 15,253
  • 21
  • 95
  • 158

1 Answers1

1

The AbstractMessageBrokerConfiguration provides this bean:

@Bean
public CompositeMessageConverter brokerMessageConverter() {

You need to inject this bean into your MessageChannelInterceptorAdapter and call its fromMessage(Message<?> message, Class<?> targetClass):

Notification notification = (Notification) this.messageConverter.fromMessage(message, Notification.class);
Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • Thanks. BTW: some clue about to avoid `stompHeaderAccessor.getDestination().equals("/app/ws/notification")` in the `if` statement? I mean, I must do use that to use the `fromMessage` working with the `Notification` type explicitly. – Manuel Jordan May 18 '18 at 21:41
  • 1
    No, that's not. The `@MessageMapping` routing logic is done later after the `MessageChannel`. You can consider to use an AOP Advice on your `@MessageMapping` methods instead. And this way you really would have the full access to the target arguments and so on. – Artem Bilan May 18 '18 at 21:43
  • Interesting. I thought and tried prior to create this post the following `if(payload.getClass().equals(Notification.class.getClass()))` and it does not work. That's why I use `stompHeaderAccessor.getDestination().equals("/app/ws/notification")` in the `if` statement. Your suggestion has sense of course – Manuel Jordan May 18 '18 at 21:53