skip to content

JMS MessageConverter

A MessageConverter turns domain objects into JMS messages and back, with a type-id header carrying the class for polymorphic payloads. Interviewers ask about that header because trusting a class name from the wire is a deserialization risk.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

explore

questions

5

What is a JMS MessageConverter in Spring, and what does the default SimpleMessageConverter do?

level: juniorimportance: must knowfreq 55%

answer

  1. toMessage / fromMessage — two methods
  2. Default = SimpleMessageConverter
  3. String→Text, byte[]→Bytes, Map→Map, Serializable→Object
  4. convertAndSend / receiveAndConvert
  5. Boot auto-wires a single MessageConverter bean

basics

~10 s

A MessageConverter turns your Java objects into a jakarta.jms.Message (and back), so you send objects instead of raw messages. The default, SimpleMessageConverter, maps String, byte[], Map, and Serializable to matching message types automatically.

solid answer

~40 s

Spring's org.springframework.jms.support.converter.MessageConverter is a two-method strategy: toMessage(Object, Session) builds a jakarta.jms.Message when you send, and fromMessage(Message) rebuilds the object when you receive. JmsTemplate.convertAndSend and @JmsListener use it so your code deals in domain objects, not TextMessage/BytesMessage plumbing. The out-of-the-box implementation is SimpleMessageConverter: a String becomes a TextMessage, a byte[] becomes a BytesMessage, a Map<String,?> becomes a MapMessage, and any other java.io.Serializable becomes an ObjectMessage (Java serialization). Anything not matching those categories throws MessageConversionException. It's zero-config and fine for simple/homogeneous JVM-to-JVM cases, but ObjectMessage ties both ends to identical classes and carries Java-serialization risk, so JSON converters are usually preferred for real payloads.

code

java · 21 lines
java
// Send a domain object without touching JMS Message types
@Service
class OrderPublisher {
    private final JmsTemplate jmsTemplate;
    OrderPublisher(JmsTemplate jmsTemplate) { this.jmsTemplate = jmsTemplate; }

    void publish(OrderCreated event) {
        // The configured MessageConverter turns 'event' into a jakarta.jms.Message.
        // With the default SimpleMessageConverter and a Serializable event,
        // this produces an ObjectMessage.
        jmsTemplate.convertAndSend("orders", event);
    }
}

@Component
class OrderListener {
    @JmsListener(destination = "orders")
    void onOrder(OrderCreated event) { // fromMessage produced this argument
        // handle event
    }
}

go deeper

for a junior

Know the two methods and that a converter maps objects to/from JMS messages; name SimpleMessageConverter as the default.

for a middle

Recite the four SimpleMessageConverter mappings and where the converter is wired (JmsTemplate, listener factory).

for a senior

Explain ObjectMessage coupling and security downsides and why JSON is usually preferred.

for a principal

Frame converter choice as a contract/interop/security decision across services and languages.

## The problem it solves The JMS API speaks in terms of `jakarta.jms.Message` subtypes: `TextMessage` (a String body), `BytesMessage` (raw bytes), `MapMessage` (name/value pairs), `ObjectMessage` (a serialized Java object), and `StreamMessage`. Writing producer/consumer code directly against these is verbose. Spring introduces the **`MessageConverter`** abstraction so you can send and receive *domain objects*. ## The interface `org.springframework.jms.support.converter.MessageConverter` has exactly two methods: - `Message toMessage(Object object, Session session)` — called on the **send** side to serialize your object into a JMS `Message`. - `Object fromMessage(Message message)` — called on the **receive** side to deserialize the JMS `Message` back into an object. Both may throw `MessageConversionException` (and `JMSException`). ## Where it plugs in - **`JmsTemplate`** holds a converter; `convertAndSend(destination, object)` and `receiveAndConvert(destination)` use it. Set it via `JmsTemplate.setMessageConverter(...)`. - **Listeners**: `@JmsListener` methods are backed by a `DefaultJmsListenerContainerFactory`, which also has `setMessageConverter(...)`. The converter turns the incoming `Message` into the listener method's argument. - **Spring Boot**: if you declare a single `@Bean` of type `MessageConverter`, Boot auto-injects it into both the auto-configured `JmsTemplate` and the default listener container factory. ## SimpleMessageConverter (the default) If you configure nothing, Spring uses `SimpleMessageConverter`. Its mapping rules are fixed: | Java type (send) | JMS Message produced | |---|---| | `String` | `TextMessage` | | `byte[]` | `BytesMessage` | | `Map<String,?>` | `MapMessage` | | any other `java.io.Serializable` | `ObjectMessage` | On receive it reverses these: `TextMessage`→`String`, `BytesMessage`→`byte[]`, `MapMessage`→`Map`, `ObjectMessage`→the deserialized object. A payload that fits none of these categories (e.g. a non-serializable object) causes `MessageConversionException`. ## Gotchas - **`ObjectMessage` uses Java serialization.** Both the producer and consumer must have the *same class* (and compatible `serialVersionUID`) on their classpath. This couples deployments tightly and makes cross-language messaging impossible. - **Security.** Deserializing untrusted `ObjectMessage` payloads is a classic remote-code-execution vector. For anything crossing a trust boundary, prefer JSON (`MappingJackson2MessageConverter`). - **It is not JSON.** SimpleMessageConverter does *not* produce JSON; a plain POJO becomes a binary `ObjectMessage`, not text. ## When to use what - SimpleMessageConverter: quick internal prototypes, or when you genuinely send String/byte[]/Map. - `MappingJackson2MessageConverter`: real domain objects, versioned schemas, or cross-service/cross-language messaging.

  • Why is ObjectMessage (via SimpleMessageConverter) often discouraged in production?
    It relies on Java serialization: both ends need identical classes/serialVersionUID, it blocks non-JVM consumers, and deserializing untrusted payloads is a well-known RCE risk. JSON with MappingJackson2MessageConverter avoids all three.
  • How do you replace the default converter application-wide in Spring Boot?
    Declare a single @Bean of type MessageConverter (e.g. a configured MappingJackson2MessageConverter). Boot's auto-configuration injects it into the JmsTemplate and the default JmsListenerContainerFactory automatically.

saying these in an interview costs you the question

  • Thinking SimpleMessageConverter serializes POJOs to JSON (it produces a binary ObjectMessage)
  • Believing a converter is optional/absent — there's always one; the default is SimpleMessageConverter
  • Not realizing ObjectMessage requires identical classes on both sides

context

open as a page

How do you make Spring JMS send and receive JSON with MappingJackson2MessageConverter, and how is it wired in Spring Boot?

level: middleimportance: should knowfreq 45%

basics

~20 s

Register a MappingJackson2MessageConverter bean, set its target type to TEXT so payloads become JSON TextMessages, and set a type-id property name so the receiver knows which class to build. Spring Boot injects that single bean into both JmsTemplate and the listener factory.

open as a page

What are SimpleMessageConverter's exact type-mapping rules, and what are the pitfalls of the ObjectMessage path?

level: seniorimportance: should knowfreq 38%

basics

~10 s

SimpleMessageConverter maps String→TextMessage, byte[]→BytesMessage, Map→MapMessage, and any other Serializable→ObjectMessage (and reverses these on receive). The ObjectMessage path uses Java serialization, so both ends need identical classes and it carries deserialization security risk.

open as a page

Explain type-id header mapping (setTypeIdPropertyName / setTypeIdMappings) and how it enables polymorphic JSON payloads over JMS.

level: seniorimportance: should knowfreq 35%

basics

~20 s

On send, MappingJackson2MessageConverter writes an identifier for the payload class into a JMS string property named by setTypeIdPropertyName. On receive it reads that id to choose the class to deserialize into. setTypeIdMappings maps short logical ids to classes so different payload types can share one queue.

open as a page

As an architect, how would you choose and govern a JMS message-conversion strategy across many services, considering versioning, interop, and security?

level: principalimportance: nice to knowfreq 20%

basics

~20 s

Standardize on JSON via MappingJackson2MessageConverter with stable logical type-ids (setTypeIdMappings), a tolerant ObjectMapper for backward/forward compatibility, and no untrusted Java deserialization. Treat the type-id map and schema as a shared, versioned contract owned across teams.

open as a page