How do you make Spring JMS send and receive JSON with MappingJackson2MessageConverter, and how is it wired in Spring Boot?
answer
- MappingJackson2MessageConverter → JSON via Jackson
- setTargetType(TEXT) else default BYTES
- setTypeIdPropertyName required for receive
- One @Bean → Boot wires template + factory
- Missing type-id → MessageConversionException
basics
~20 sRegister 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.
solid answer
~40 sUse org.springframework.jms.support.converter.MappingJackson2MessageConverter, which serializes objects to JSON with Jackson. Configure setTargetType(MessageType.TEXT) so it writes a TextMessage (default is BYTES → BytesMessage), and setTypeIdPropertyName("_type") so it stamps a JMS string property identifying the payload type; the receiver reads that property to pick the target class via Jackson. In Spring Boot you just expose one @Bean MessageConverter — auto-configuration wires it into the auto-configured JmsTemplate and the DefaultJmsListenerContainerFactory, so both send and receive use JSON. Without Boot you set it explicitly on JmsTemplate.setMessageConverter and the container factory. The type-id property is mandatory for receiving: fromMessage throws MessageConversionException if it can't find that property, because the converter must know what Java type to deserialize into.
code
java · 16 linesimport org.springframework.jms.support.converter.MappingJackson2MessageConverter;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.converter.MessageType;
@Configuration
class JmsConfig {
@Bean // single MessageConverter bean — Boot injects it into JmsTemplate + listener factory
MessageConverter jacksonJmsMessageConverter(ObjectMapper objectMapper) {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setObjectMapper(objectMapper); // reuse app-wide mapper (JavaTimeModule, etc.)
converter.setTargetType(MessageType.TEXT); // JSON as TextMessage instead of default BytesMessage
converter.setTypeIdPropertyName("_type"); // required so fromMessage knows the target class
return converter;
}
}go deeper
Know that MappingJackson2MessageConverter gives JSON and needs a bean.
Configure targetType and typeIdPropertyName and explain Boot's single-bean wiring into template and factory.
Discuss ObjectMapper customization (time module, unknown-properties tolerance) and consistent config across services.
Treat the JSON converter as a versioned wire contract shared by many services and languages.
## Why JSON `SimpleMessageConverter` turns POJOs into `ObjectMessage` (Java serialization) — brittle and JVM-only. `MappingJackson2MessageConverter` (package `org.springframework.jms.support.converter`) instead serializes objects to **JSON** using a Jackson `ObjectMapper`, giving human-readable, language-neutral, schema-tolerant payloads. ## Key configuration knobs - **`setTargetType(MessageType)`** — controls the JMS body form. `MessageType.TEXT` → JSON inside a `TextMessage` (readable, common). `MessageType.BYTES` → JSON bytes inside a `BytesMessage` (the default; more compact/binary-safe). Pick TEXT when you want to eyeball messages in broker consoles. - **`setTypeIdPropertyName(String)`** — the name of a JMS **string property** the converter writes on send and reads on receive to determine the Java type. This is effectively required for the round trip: on `fromMessage`, if this property name is unset or the property is missing on the message, it throws `MessageConversionException("Could not find type id property ...")`. Jackson needs a concrete target type to deserialize JSON into. - **`setObjectMapper(ObjectMapper)`** — supply a customized mapper (JavaTimeModule, naming strategy, failOnUnknownProperties=false for forward compatibility, etc.). - **`setTypeIdMappings(Map<String,Class<?>>)`** — optional; maps short logical ids to classes instead of using fully-qualified class names (covered in the polymorphism question). ## Wiring — Spring Boot Spring Boot's JMS auto-configuration checks for a user-defined `MessageConverter` bean. If exactly one exists, it is injected into: - the auto-configured **`JmsTemplate`**, and - the default **`DefaultJmsListenerContainerFactory`** used by `@JmsListener`. So a single `@Bean MessageConverter` bean makes both sending and receiving speak JSON — no further wiring. ## Wiring — plain Spring Without Boot you set it yourself: `jmsTemplate.setMessageConverter(converter)` and `factory.setMessageConverter(converter)` on your `DefaultJmsListenerContainerFactory`. ## Round-trip mechanics - **Send**: `toMessage` serializes the object to JSON, creates a TextMessage/BytesMessage, and writes the type-id string property. - **Receive**: `fromMessage` reads the type-id property → resolves a `Class` (via `typeIdMappings` or by treating the id as an FQCN) → asks Jackson to parse the JSON into that type → returns the object, which the listener adapter passes to your `@JmsListener` method. ## Gotchas - **Both ends must share the same type-id property name.** A producer using `_type` and a consumer expecting `typeId` will fail with `MessageConversionException` on receive. - **Missing type-id.** Sending with a converter that has no `typeIdPropertyName` set, then receiving with one that does (or vice-versa), breaks. Configure both consistently. - **Dependency.** Requires Jackson on the classpath (`com.fasterxml.jackson`). With `spring-boot-starter-web` it's already present. - **Target type mismatch is fine for humans, not for parsing.** TEXT vs BYTES must be a producer choice; the consumer converter parses whichever body it receives, but keep it consistent to avoid confusion.
- What is the difference between setTargetType(TEXT) and the default BYTES?TEXT writes the JSON into a TextMessage — readable in broker tooling; BYTES (the default) writes JSON bytes into a BytesMessage — more compact and binary-safe. Both carry the same JSON; it's just the JMS body form.
- What happens on receive if you forget to set typeIdPropertyName?fromMessage cannot determine the target Java type, so it throws MessageConversionException ("Could not find type id property ..."). The property name must be set and present on the incoming message.
saying these in an interview costs you the question
- Assuming JSON works with zero config — you must register the converter and set typeIdPropertyName
- Thinking the default targetType is TEXT (it's BYTES)
- Configuring different type-id property names on producer vs consumer