I'm trying to send an ObjectMessage
using ActiveMQ Classic. For this purpose I created two Spring Boot projects - customer and producer. I use the code below to sent from producer.
@GetMapping("/send-letter")
public String sendLetter() {
var letter = new Letter("Hello " + UUID.randomUUID(), "Jack", "Jill");
template.convertAndSend("test_letter", letter);
return "Letter sent!";
}
Then, I use the code below to catch that object in the customer.
@JmsListener(destination = "test_letter")
public void getTest(Letter letter) {
System.out.printf("From %s to %s with content %s", letter.getSender(), letter.getReceiver(), letter.getContent());
}
Also, this is my configuration on my application.yaml
file. I also tried to use trust-all: true
parameter but didn't have any effect.
spring:
activemq:
broker-url: tcp://localhost:61616
user: admin
password: admin
packages:
trusted: com.example.demo.Entities.Letter
The exact same structure works with strings.
I am able to send the ObjectMessage
to ActiveMQ as I can see from the admin panel, but when I run the listener it's throwing a bunch of errors which I put the "main" ones below:
org.springframework.jms.listener.adapter.ListenerExecutionFailedException: Listener method 'public void com.example.demo.controller.MessageConsumer.getTest(com.example.demo.Entities.Letter)' threw exception
at org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:118)
Caused by: org.springframework.jms.support.converter.MessageConversionException: Could not convert JMS message
at org.springframework.jms.listener.adapter.AbstractAdaptableMessageListener.extractMessage(AbstractAdaptableMessageListener.java:255)
Caused by: jakarta.jms.JMSException: Failed to build body from content. Serializable class not available to broker. Reason: java.lang.ClassNotFoundException: Forbidden class com.example.demo.Entities.Letter! This class is not trusted to be serialized as ObjectMessage payload. Please take a look at http://activemq.apache.org/objectmessage.html for more information on how to configure trusted classes.
at org.apache.activemq.util.JMSExceptionSupport.create(JMSExceptionSupport.java:49) ~[activemq-client-jakarta-5.18.2.jar:5.18.2]
Caused by: java.lang.ClassNotFoundException: Forbidden class com.example.demo.Entities.Letter! This class is not trusted to be serialized as ObjectMessage payload. Please take a look at http://activemq.apache.org/objectmessage.html for more information on how to
I wrote the code by reading this tutorial. I read and tried the every answer that i could found about this (including converting object to byte) but i couldn't make them work.
I was expecting the see the object in costumer console.
It looks like you configured the trusted packages to use the class name (i.e. com.example.demo.Entities.Letter
) rather than the package name (i.e. com.example.demo.Entities
). Try using this instead:
spring:
activemq:
broker-url: tcp://localhost:61616
user: admin
password: admin
packages:
trusted: com.example.demo.Entities
That said, you should avoid using JMS ObjectMessage
whenever possible. They depend on Java serialization to marshal and unmarshal their object payload. Not only is this slow, but it is also generally considered unsafe because a malicious payload can exploit the host system. Lots of CVEs have been created for this and is the reason why you must explicitly configure which packages are trusted in the first place. Using ObjectMessage
also limits the flexibility of your architecture since non-JMS clients can't consume them.
I strongly recommend using some other format for your messages, e.g. JSON, XML, Protobuf, etc. This will be faster, safer, and broadly compatible with other languages and protocols making your architecture more robust.