You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ActiveMQBytesMessage读取报错:Message body is write-only问题咨询

解决ActiveMQBytesMessage的"Message body is write-only"异常

问题重现

编写JUnit测试断言ACK消息时,创建ActiveMQBytesMessage作为输出消息,调用messageHandlerBean.onMessage()后读取消息内容抛出异常。调试可见消息体已填充,但无法读取。

测试代码:

@ExtendWith(MockitoExtension.class)
class MessageHandlerBeanTest {

    //... @Mock

    @InjectMocks
    MessageHandlerBean messageHandlerBean;


    private BytesMessage inputMsg;

    private BytesMessage outputMsg;


    void setMessageContent(String xml) {
        try {
            inputMsg.clearBody();
            inputMsg.writeBytes(xml.getBytes(StandardCharsets.UTF_8));  // for some reason writeUTF() does not encode correctly
        } catch (JMSException e) {
            throw new RuntimeException(e);
        }
    }


    @BeforeEach
    void setUp() {

        //...

        inputMsg = new ActiveMQBytesMessage();
        setMessageContent(envelope);

        outputMsg = new ActiveMQBytesMessage();
        Mockito.when(currSession.createBytesMessage()).thenReturn(outputMsg);

    }


    @Test
    void valid_msg_returns_ok() throws Exception {

        messageHandlerBean.onMessage(inputMsg);
    
        Assertions.assertThat(outputMsg.getBodyLength()).isNotZero();
        Assertions.assertThat(outputMsg.readUTF()).isEqualTo("<xml>...<xml>");
    }
}

抛出的异常:

javax.jms.MessageNotReadableException: Message body is write-only

    at org.apache.activemq.command.ActiveMQBytesMessage.checkWriteOnlyBody(ActiveMQBytesMessage.java:819)
    at org.apache.activemq.command.ActiveMQBytesMessage.initializeReading(ActiveMQBytesMessage.java:824)
    at org.apache.activemq.command.ActiveMQBytesMessage.getBodyLength(ActiveMQBytesMessage.java:182)

原因分析

ActiveMQBytesMessage存在写模式和读模式的切换机制:

  • 刚创建的消息处于写模式,此时可以调用writeBytes()等写入方法填充内容;
  • 写入完成后,消息仍保持写模式,直接调用getBodyLength()、readUTF()等读取方法会触发"write-only"异常;
  • 必须显式切换到读模式才能读取消息体内容。

解决方案

在读取outputMsg之前,调用reset()方法将消息切换到读模式,并重置读取指针到消息体开头:

修改后的测试方法:

@Test
void valid_msg_returns_ok() throws Exception {

    messageHandlerBean.onMessage(inputMsg);

    // 切换到读模式
    outputMsg.reset();
    
    Assertions.assertThat(outputMsg.getBodyLength()).isNotZero();
    Assertions.assertThat(outputMsg.readUTF()).isEqualTo("<xml>...<xml>");
}

reset()方法会完成以下操作:

  1. 将消息从写模式切换为读模式;
  2. 重置消息体的读取指针到起始位置;
  3. 清除任何未完成的写入操作标记。

内容的提问来源于stack exchange,提问作者anat0lius

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 19:23:10