Search code examples
javaspringspring-bootwebsocketspring-websocket

Unable to send reply using WebSocket


I found a lot of tutorials and everything looks right to me, but the client never recieve the response message. The connection is working and the method on the controller is being called, but the subscription by the client looks like its being ignored.

Configuration class:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setApplicationDestinationPrefixes("/app");
        registry.enableSimpleBroker("/topic");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
        stompEndpointRegistry.addEndpoint("/unify")
            .withSockJS();
    }

}

Controller class:

@Controller
public class StatusController {
    @MessageMapping("/status")
    @SendTo("/topic/reply")
    public String status(@Payload String test) {
        return test;
    }
}

Test class:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class WebSocketConnectionTest {

    @Value(${local.server.port})
    private String port;

    @Test
    public void testResponse() {

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

        boolean exceptionThrowed = false;
        final CompletableFuture<String> completableFuture = new CompletableFuture<>();

        try {

            StompSession session = stompClient.connect("ws://localhost: " + port + "/unify", new StompSessionHandlerAdapter() {}).get(1, TimeUnit.SECONDS);

            session.subscribe("/topic/reply", new StompFrameHandler() {

                @Override
                public Type getPayloadType(StompHeaders headers) {
                    return String.class;
                }

                @Override
                public void handleFrame(StompHeaders headers, Object payload) {
                    completableFuture.complete((String)payload);
                }

            });

            session.send("/app/status", "test");

            // Always fails
            String resp = completableFuture.get(5, TimeUnit.SECONDS);

        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            e.printStackTrace(); // Always timeout exception
            exceptionThrowed = true;
        }

        Assert.assertFalse(exceptionThrowed);

    }

    private List<Transport> createTransportClient() {
        List<Transport> transports = new ArrayList<>(1);
        transports.add(new WebSocketTransport(new StandardWebSocketClient()));
        return transports;
    }

}

I'm sure that I'm missing something very simple, but I've been trying different configurations for two days without success.


Solution

  • Solution

    Looks like the response class needs to have a field "content" of any type and a correspondent getContent() (don't know if the getContent() is really nessessary).