Here's what I'm trying to do:
Application 1 (consumer)
com.producer.model.Event - simple serialisable model (id, name)
Application 2 (producer)
com.consumer.integration.model.Event - simple serialisable model (id, name)
Serialisation configuration
@Bean
public MessageConverter jacksonJmsMessageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
converter.setTypeIdPropertyName("_type");
return converter;
}
Now when I produce a message
@Override
public void publishEvent(Event event) {
log.debug("Publish event Event : {}", event);
jmsTemplate.convertAndSend(eventTopic, event);
}
The consumer
@Override
@JmsListener(destination = "${jmsConfig.eventTopic}", containerFactory = "topicListenerFactory")
public void handleEvent(Event event) {
log.debug("Received an event {}", event);
}
The consumer side complains that the packages of the models are different.
MessageConversionException: Failed to resolve type id [com.producer.model.Event]
...
Caused by: java.lang.ClassNotFoundException: com.producer.model.Event
So deserialisation fails in the consumer because it can't find the package passed on with _type value.
Why do we even need to pass any package related info? It leaks information that is not needed...
What is the correct way to handle these situations. It should be quite a usual case?
EDIT:
With the help of Gary Russell I got it solved. Here's what you'd want to do.
Define a mapper in the producer AND the consumer with desired typings:
@Bean
public MessageConverter jacksonJmsMessageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
HashMap<String, Class<?>> typeIdMappings = new HashMap<>();
typeIdMappings.put(Event.class.getSimpleName(), Event.class);
converter.setTypeIdMappings(typeIdMappings);
converter.setTypeIdPropertyName("_type");
return converter;
}
It's important that
setTypeIdPropertyNamematches in the consumer and the producersetTypeIdMappingskeys match in the consumer and the producer
This way you could match multiple objects between two services with one mapper.