I would like to understand why I need to mark the getMessageConverter
and classMapper
methods with @Bean
even setting them directly in my custom RabbiteTemplate.
Without the @Bean
and passing them to private
, the message not contains the TypeId
correctly in the message.
So, with the @Bean and public methods, I had the correct header on the message:
headers: __TypeId__: OrderProducer
Without them, the message contains the incorrect TypeId:
headers: __TypeId__: com.projet.order.message.OrderProducer
What is the default behavior without the classMapper.
See the code:
@Bean(name = "sendCommandOrderCreate")
public RabbitTemplate sendCommandOrderCreate() {
RabbitTemplate rabbitTemplate = createRabbitTemplate(getMessageConverter());
rabbitTemplate.setExchange("order.exchange");
rabbitTemplate.setRoutingKey("order.cmd.create");
return rabbitTemplate;
}
private RabbitTemplate createRabbitTemplate(final MessageConverter messageConverter) {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(messageConverter);
return rabbitTemplate;
}
@Bean
public Jackson2JsonMessageConverter getMessageConverter() {
Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
jackson2JsonMessageConverter.setClassMapper(classMapper());
return jackson2JsonMessageConverter;
}
@Bean
public DefaultClassMapper classMapper() {
DefaultClassMapper classMapper = new DefaultClassMapper();
Map<String, Class<?>> idClassMapping = new HashMap<>();
idClassMapping.put(OrderProducer.class.getSimpleName(), OrderProducer.class);
idClassMapping.put(OrderConsumer.class.getSimpleName(), OrderConsumer.class);
classMapper.setIdClassMapping(idClassMapping);
return classMapper;
}
And how I'm injecting the bean in a Service:
public OrderService(@Qualifier("sendCommandOrderCreate") RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
}
I found the problem. I resolved using another Mapper: DefaultJackson2JavaTypeMapper
.
private DefaultJackson2JavaTypeMapper classMapper() {
DefaultJackson2JavaTypeMapper classMapper = new DefaultJackson2JavaTypeMapper();
Map<String, Class<?>> idClassMapping = new HashMap<>();
idClassMapping.put(OrderProducer.class.getSimpleName(), OrderProducer.class);
idClassMapping.put(OrderConsumer.class.getSimpleName(), OrderConsumer.class);
classMapper.setIdClassMapping(idClassMapping);
return classMapper;
}
I could found this mapper after debugging the code and looking for the different implementations of ClassMapper. The DefaultClassMapper
can't provide the behavior that I was expecting and I cant' explain why declare it with @Bean
could change his behavior (maybe is a bug on Spring).