StompFrameHandler doesn't get payload from message
Asked Answered
T

5

5

Finally I have my websocket client connecting to the endpoint but I can't extract message payload. I can get headers but payload is not recognized.

My WebSocket client looks like below:

    WebSocketTransport webSocketTransport = new WebSocketTransport(standardWebSocketClient);
    SockJsClient sockJsClient = new SockJsClient(Arrays.asList(webSocketTransport));
    WebSocketStompClient stompClient = new WebSocketStompClient(sockJsClient);

    stompClient.setMessageConverter(new StringMessageConverter());

    StompSessionHandler sessionHandler = new MyStompSessionHandler();
    ListenableFuture<StompSession> connect = stompClient.connect(URL, sessionHandler);

        StompSession stompSession = connect.get();
        System.out.println("sessionId: " + stompSession.getSessionId());

        String path = "/queue/orders";

        stompSession.subscribe(path, new MySimpleStompFrameHandler());

Stomp Frame Handler:

    private class MySimpleStompFrameHandler implements StompFrameHandler {

    @Override
    public Type getPayloadType(StompHeaders stompHeaders) {
        System.out.println("Headers " + stompHeaders.toString());
        return String.class;
    }

    @Override
    public void handleFrame(StompHeaders stompHeaders, Object payload) {
        System.out.println("Msg " + payload.toString());
        completableFuture.complete(payload.toString());
    }
}

I have headers written in the terminal but there is nothing from handleFrame method. Any idea ?

Edited: After debugging i see that the problem is in DefaultStompSession class which uses my implementation of frameHandler

    private void invokeHandler(StompFrameHandler handler, Message<byte[]> message, StompHeaders stompHeaders) {
    if (message.getPayload().length == 0) {
        handler.handleFrame(stompHeaders, null);
        return;
    }
    Type type = handler.getPayloadType(stompHeaders);
    Class<?> payloadType = ResolvableType.forType(type).resolve();
    Object object = getMessageConverter().fromMessage(message, payloadType);
    if (object == null) {
        throw new MessageConversionException("No suitable converter, payloadType=" + payloadType +
                ", handlerType=" + handler.getClass());
    }
    handler.handleFrame(stompHeaders, object);
}

Problem is after this line Type type = handler.getPayloadType(stompHeaders); After that nothing more is executed and my program just ends so handleFrame() is not even executed. What is wrong there ? Maybe with Type returned from getPayloadType - I choose String because I think every message can be presented as string.

Tenfold answered 29/1, 2018 at 13:16 Comment(1)
Still struggling with this problem. Any idea ?Tenfold
C
8

I had a similar issue.

The problem was that I had specified stompClient.setMessageConverter(new StringMessageConverter());, while a JSON was passed as payload.

Solution (for my issue): stompClient.setMessageConverter(new MappingJackson2MessageConverter());

What you can do to find a solution:

  • Throw (or log) when an exception is triggered. For your case, you should add an override for the following method in MyStompSessionHandler:

     @Override
     public void handleException(StompSession session, StompCommand command, StompHeaders headers, byte[] payload, Throwable exception) {
         throw new RuntimeException("Failure in WebSocket handling", exception);
     }
    
  • While debugging invokeHandler, check the content of the payload. If you are able to execute the code, you can do this by executing new String((byte[]) message.getPayload()).

Chrysa answered 2/11, 2018 at 14:24 Comment(1)
you saved my day, i used this line new String((byte[]) message.getPayload()) and i was able to do my custom implementation, thanksUltrastructure
R
0

I got your point you need to extend StompSessionHandlerAdapter implement StompFrameHandler.

I tried something for you :

public class MySimpleStompFrameHandler extends StompSessionHandlerAdapter implements StompFrameHandler {

private Logger logger = LogManager.getLogger(MyStompSessionHandler.class);

@Override
public void afterConnected(StompSession session, StompHeaders connectedHeaders) {
    System.out.println("Connected");
}

@Override
public void handleException(StompSession session, StompCommand command, StompHeaders 
 headers, byte[] payload, Throwable exception) {
    logger.error("Got an exception", exception);
}

@Override
public Type getPayloadType(StompHeaders headers) {
    return <payload_type>.class;
}

@Override
public void handleFrame(StompHeaders headers, Object payload) {
    <payload_type> msg = (<payload_type>) payload;
    System.out.println(msg);
    logger.info("Received : " + msg);
}

}

Where payload_type is your user-defined class which you want to convert stream data

Good to go !!

Ricky answered 26/8, 2019 at 5:35 Comment(0)
U
0

I share my implementation, hope to be usefull. I didn't set a messageconverter and did my custom implementation of method handleFrame

    WebSocketClient client = new StandardWebSocketClient();
    WebSocketStompClient stompClient = new WebSocketStompClient(client);
    StompSessionHandler sessionHandler = new MyStompSessionHandler(prop);
    WebSocketHttpHeaders webSocketHttpHeaders = new WebSocketHttpHeaders();
    webSocketHttpHeaders.add("Authorization", "Bearer " + token);

    StompSession session = stompClient.connect(endpoint, webSocketHttpHeaders, sessionHandler).get();

and then handling the message sent, in my case a JSON String Object

    @Override
    public Type getPayloadType(StompHeaders headers) {
        return null;
    }

    @Override
    public void handleFrame(StompHeaders headers, Object payload) {
        String cadena = new String((byte[]) payload);
        JsonParser parser = new JsonParser();
        JsonObject obj = parser.parse(cadena).getAsJsonObject();
        System.out.println(obj.toString());
    }   
Ultrastructure answered 4/9, 2019 at 15:38 Comment(0)
R
0

It's need define MessageConverter and then implement method getPayloadType with object type JSON

SockJsClient sockJsClient = new SockJsClient(transports);
WebSocketStompClient stompClient = new WebSocketStompClient(sockJsClient);
stompClient.setMessageConverter(**new MappingJackson2MessageConverter()**);

....

public class SockJsWebsocketSubscriptionHandler implements StompFrameHandler {
    @Override
    public Type getPayloadType(StompHeaders headers) {
        return **HelloMessage.class;**
    }
...
}
Rig answered 24/6, 2021 at 18:27 Comment(0)
L
0

Only to extend the existing answers. When is used thestompClient.setMessageConverter(new MappingJackson2MessageConverter()); to force jackson to serialize and deserialize the class, check that the class to be serialized is correct and it is not missing the default constructor, setters and getters, ... If not, the behavior is as described in this question: getPayloadType is executed, but handleFrame is not. No error is shown on the system (still with logs in TRACE for websockets) but nothing is received on the client.

Libby answered 9/1 at 8:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.