How to send object in message with EmbeddedActiveMQ

Viewed 33

This is another problem that found when migrating EmbeddedJMS to EmbeddedActiveMQ: How to migrate from deprecated EmbeddedJMS to recommended EmbeddedActiveMQ

Previously to send message with object used

try {
    producer.send(session.createObjectMessage(message));
    session.commit();
} catch (JMSException e) {
    log.error(e);
}

Where message object is just serializable.

With new approach those classes does not match and use this to produce message:

try {
    final ClientMessage msg = clientSession.createMessage(true);
    try(ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos)) {
        oos.writeObject(message);
        oos.flush();
        msg.writeBodyBufferBytes(baos.toByteArray());
        clientProducer.send(msg);
        clientSession.commit();
    }
} catch(ActiveMQException | IOException e) {
    throw new RuntimeException(e);
}

To read it assumed that need to do it backwards like this:

ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(clientMessage.getBodyBuffer().toByteBuffer().array());
ObjectInputStream objectInputStream = null;
try {
    objectInputStream = new ObjectInputStream(arrayInputStream);
    objectInputStream.readObject();
} catch(IOException | ClassNotFoundException e) {
    throw new RuntimeException(e);
}

However this does not work, there is exception:

java.io.StreamCorruptedException: invalid stream header: 000000B2

Anything that I'm missing? Is there any more efficient/elegant way to do this?

1 Answers

You should continue to use your JMS Connections, Sessions, MessageConsumers, MessageProducers, etc. Just because you switch to EmbeddedActiveMQ doesn't mean you need to change any of your clients (aside from perhaps some JNDI-related code). JMS is still supported.

Aside from that I would strongly discourage you from using JMS ObjectMessage. They depend on Java serialization to marshal and unmarshal their object payload. This process is generally considered unsafe, because a malicious payload can exploit the host system. Lots of CVEs have been created for this which is why most JMS providers force users to explicitly whitelist packages that can be exchanged using ObjectMessage messages. Aside from the security issues Java serialization is slow.

There are also a number of other issues with using JMS ObjectMessage not related to security that you should read about. This article has a good suggestion for how to replace ObjectMessage - define a data representation for the payload (JSON, protobuf, XML) and use TextMessage or BytesMessage to carry it.

Related