I am using Spring Boot framework. I want to send an object from a service to another service via RabbitMQ like this:
Service A:
rabbitTemplate.convertAndSend("queue", createAccountRequestMessage);
Service B:
@RabbitListener(queues = "queue")
public void onAccountRequested(@Valid CreateAccountRequestMessage createAccountRequestMessage, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG, long tag) throws IOException
{
}
In CreateAccountRequestMessage
class I have defined some validation annotations like @NotEmpty
, @NotNull
and etc, but when I'm sending wrong message from service A to service B, @Valid
annotation doesn't work and CreateAccountRequestMessage
object is not validated before invoke onAccountRequested
method.
You need to set the validator in DefaultMessageHandlerMethodFactory
.
@Autowired
SmartValidator validator;
@Bean
public DefaultMessageHandlerMethodFactory messageHandlerMethodFactory() {
DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
factory.setValidator(this.validator);
return factory;
}
Then you also need to specify the @Payload
annotation along with the @Valid
annotation.
@RabbitListener(queues = "queue")
public void onAccountRequested(@Valid @Payload CreateAccountRequestMessage
createAccountRequestMessage, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG, long tag) throws IOException
{
}
Now MethodArgumentNotValidException
will be thrown and the message will be discarded, or you can send the message to a dead letter exchange.
I had the same problem. The answer of @Praveer works well except SmartValidator. I post here my solution, which is inspired by this article https://blog.trifork.com/2016/02/29/spring-amqp-payload-validation/
@Configuration
@EnableRabbit
@Slf4j
public class CmsMQConfig implements RabbitListenerConfigurer {
@Value("${dw.rabbitmq.hosts}")
private String hosts;
@Value("${dw.rabbitmq.username}")
private String username;
@Value("${dw.rabbitmq.password}")
private String password;
@Value("${dw.rabbitmq.virtual-host}")
private String virtualHost;
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory());
factory.setMessageConverter(messageConverter());
return factory;
}
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setAddresses(hosts);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
connectionFactory.setVirtualHost(virtualHost);
return connectionFactory;
}
@Bean
public Jackson2JsonMessageConverter messageConverter() {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return new Jackson2JsonMessageConverter(mapper);
}
@Bean
public DefaultMessageHandlerMethodFactory defaultHandlerMethodFactory() {
DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
factory.setValidator(amqpValidator());
return factory;
}
@Bean
public Validator amqpValidator() {
return new OptionalValidatorFactoryBean();
}
@Override
public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) {
registrar.setContainerFactory(rabbitListenerContainerFactory());
registrar.setMessageHandlerMethodFactory(defaultHandlerMethodFactory());
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With