I have a use case where I need to convert a message from one type to another (i.e. TextMessage -> ObjectMessage).
I found that when diverting between queues there is an option to transform the message. I have implemented the Transformer interface as instructed in the documentation.
import org.apache.activemq.artemis.api.core.Message;
import org.apache.activemq.artemis.core.server.transformer.Transformer;
import javax.jms.ObjectMessage;
public class TypeTransformer implements Transformer {
@Override
public Message transform(Message message) {
return message;
}
}
But I am now beginning to realize that it might be impossible to convert from a org.apache.activemq.artemis.api.core.Message to an javax.jms.ObjectMessage?
Is this right? That it cannot be done or is there some other way?
It should technically be possible to convert a javax.jms.TextMessage to a javax.jms.ObjectMessage, but it may be cumbersome. Here are some important things to note:
javax.jms.TextMessage, javax.jms.ObjectMessage, and org.apache.activemq.artemis.api.core.Message are all just interfaces. The javax version is what you use on the client and Message is what is used on the broker. The data for each type of message is stored differently in the underlying message implementation.ObjectMessage will need to be on the broker's classpath. This isn't required under normal circumstances as the broker itself will never serialize or deserialize the object.ObjectMessage whenever possible. ObjectMessage objects depend on Java serialization to marshal and unmarshal their object payload. This process is generally considered unsafe (and slow!), because a malicious payload can exploit the host system. Lots of CVEs have been created for this. For this reason, most JMS providers force users to explicitly whitelist packages that can be exchanged using ObjectMessage messages. For example, here's the related documentation for ActiveMQ Artemis. There are a number of other issues with using JMS ObjectMessage not related to security that you should read about.Granted you understand all that you should be able to convert the message using code something like this:
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import org.apache.activemq.artemis.api.core.ICoreMessage;
import org.apache.activemq.artemis.api.core.Message;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.core.server.transformer.Transformer;
public class TypeTransformer implements Transformer {
@Override
public Message transform(Message message) {
ICoreMessage coreMessage = message.toCore();
try {
// get the data from the TextMessage
SimpleString mySimpleString = coreMessage.getBodyBuffer().readNullableSimpleString();
if (mySimpleString == null) {
// no text in the message so no transformation can be done
return message;
}
String myString = mySimpleString.toString();
// parse the data from the TextMessage and set it on the serializable object
Serializable object = new MySerializable();
// turn serializable object into byte array and write it to the message
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
oos.flush();
byte[] data = baos.toByteArray();
coreMessage.getBodyBuffer().clear();
coreMessage.getBodyBuffer().writeInt(data.length);
coreMessage.getBodyBuffer().writeBytes(data);
coreMessage.setType(Message.OBJECT_TYPE);
return coreMessage;
} catch (Exception e) {
e.printStackTrace();
return message;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With