StompSession send() ClassCastException

hyng·2023년 1월 23일
0

smilegate-winter-dev-camp

목록 보기
7/15

Caused by: java.lang.ClassCastException: class com.example.chat.dto.ChatMessage cannot be cast to class [B (com.example.chat.dto.ChatMessage is in unnamed module of loader 'app'; [B is in module java.base of loader 'bootstrap')
at org.springframework.web.socket.messaging.WebSocketStompClientStompWebSocketMessageCodec.encode(WebSocketStompClient.java:580)atorg.springframework.web.socket.messaging.WebSocketStompClientStompWebSocketMessageCodec.encode(WebSocketStompClient.java:580) at org.springframework.web.socket.messaging.WebSocketStompClientWebSocketTcpConnectionHandlerAdapter.sendAsync(WebSocketStompClient.java:465)
at org.springframework.messaging.simp.stomp.DefaultStompSession.execute(DefaultStompSession.java:290)
... 107 more

다음 링크를 참조하여 websocket 테스트를 작성하는데, 계속 ClassCastException이 발생했다.

@BeforeEach
  void init() throws ExecutionException, InterruptedException, TimeoutException {
    webSocketStompClient = new WebSocketStompClient(
      new SockJsClient(
        List.of(new WebSocketTransport(new StandardWebSocketClient()))));
    session = webSocketStompClient.connectAsync(
                                                      String.format("ws://localhost:%d/ws", port),
                                                      new StompSessionHandlerAdapter() {
                                                      })
                                                    .get(1000, TimeUnit.SECONDS);
    webSocketStompClient.setMessageConverter(new MappingJackson2MessageConverter());
  }

  @Nested
  @DisplayName("send 메서드는")
  class DescribeSend {

    @Nested
    @DisplayName("유효한 값이 전달되면")
    class ContextWithValidData {

      @Test
      @DisplayName("해당 토픽을 구독한 사용자들에게 메시지를 발행한다")
      void ItPublishMessage() throws JsonProcessingException {
        // given
        String topicId = "topicId";
        ChatMessage message = ChatMessage.from("hi~");
        BlockingQueue<ChatMessage> queue = new ArrayBlockingQueue<>(1);
        session.subscribe(String.format("/topic/%s", topicId), new StompFrameHandler() {
          @Override
          public Type getPayloadType(StompHeaders headers) {
            return ChatMessage.class;
          }

          @Override
          public void handleFrame(StompHeaders headers, Object payload) {
            queue.add((ChatMessage) payload);
          }
        });

        // when
        StompHeaders stompHeaders = new StompHeaders();
        stompHeaders.setDestination(String.format("/chat/%s/send", topicId));
        stompHeaders.setContentType(APPLICATION_JSON);

        session.send(stompHeaders, message);

        // then
//        await()
//          .atMost(10, TimeUnit.SECONDS)
//          .untilAsserted(() -> assertEquals(message.getMessage(), queue.poll()));
      }
    }
  }
}

디버깅을 하며 쫓아가보니 다음의 코드에서 문제가 발생하고 있었다.

ChatMessage -> byte[] 로 변환하려고 하니 발생하는 문제라고 생각했다.
그래서 message 를 생성하는 코드를 디버깅해서 따라가봤다.

분명 메시지 컨버터를 MappingJackson2MessageConverter로 하였는데
기본 설정인 SimpleMessageConverter가 실행되는 게 이상했다.

따로 메시지 컨버터를 설정하지 않으면 기본으로 SimpleMessageConverter로 된다는 내용 참고

webSocketStompClient.setMessageConverter(new MappingJackson2MessageConverter());

그래서 메시지 컨버터 세팅 설정의 순서를 바꿔보니 정상적으로 동작했다.

기존코드

@BeforeEach
  void init() throws ExecutionException, InterruptedException, TimeoutException {
    webSocketStompClient = new WebSocketStompClient(
      new SockJsClient(
        List.of(new WebSocketTransport(new StandardWebSocketClient()))));
    session = webSocketStompClient.connectAsync(
                                                      String.format("ws://localhost:%d/ws", port),
                                                      new StompSessionHandlerAdapter() {
                                                      })
                                                    .get(1000, TimeUnit.SECONDS);
    webSocketStompClient.setMessageConverter(new MappingJackson2MessageConverter());
  }

변경코드

@BeforeEach
  void init() throws ExecutionException, InterruptedException, TimeoutException {
    webSocketStompClient = new WebSocketStompClient(
      new SockJsClient(
        List.of(new WebSocketTransport(new StandardWebSocketClient()))));
    webSocketStompClient.setMessageConverter(new MappingJackson2MessageConverter());
    
    session = webSocketStompClient.connectAsync(
                                                      String.format("ws://localhost:%d/ws", port),
                                                      new StompSessionHandlerAdapter() {
                                                      })
                                                    .get(1000, TimeUnit.SECONDS);
  }

테스트 성공

profile
공부하고 알게 된 내용을 기록하는 블로그

0개의 댓글