最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - @RabbitListener with MessageConverter and @Payload Object payload - Stack Overflow

programmeradmin3浏览0评论

I'm looking for a way to use the same method to receive messages converted by myMessageConverter to an object depending on __TypeId__ header.

WHY? We are migrating from IBM MQ to RabbitMQ. Currently, it works like that:

@JmsListener(destination = "${jms.topic})
public void receiveMessage(@NonNull Message<Object> message) {
    Object payload = message.getPayload();>     
    processByType(payload); 
}  

I'd like to have that something like that:

 @RabbitListener(queues = "${queue-name}", messageConverter = "myMessageConverter")
 public void receiveMessage(@Payload Object payload) { 
    // use existing logic 
    processByType(payload);
}

But in the case from above, it passes the object of type Message with all its details.

I found information that the method should have one parameter of a certain type (e.g.: MyPayload). and it works.

 @RabbitListener(queues = "${queue-name}", messageConverter = "myMessageConverter")
 public void receiveMessage(@Payload MyPayload payload) { ... }

It even works for message types inherited from a common interface, e.g., MyInboundPayload.

 @RabbitListener(queues = "${queue-name}", messageConverter = "myMessageConverter")
 public void receiveMessage(@Payload MyInboundPayload payload) { ... }

And I'd go with this option, but half of the payload types are library classes imported from other services. And I'm unable to make them implement MyInboundPayload.


So, does anyone know how to force it to pass an already converted message to the method? Is that possible?

public void receiveMessage(@Payload Object payload)

Thanks!


Current configuration:

    @Bean
    public MessageConverter myMessageConverter() {
        ObjectMapper objectMapper = new ObjectMapper()
                .registerModule(new JavaTimeModule())
                .registerModule(new ParanamerModule())
                .registerModule(new SingleArgConstructorModule("com.xyz.api"))
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        return new Jackson2JsonMessageConverter(objectMapper);
    }

p.s. I know that I can process Message and then get type and manually convert to a type. But I wonder if there is a way to make with @RabbitListener capabilities.

I'm looking for a way to use the same method to receive messages converted by myMessageConverter to an object depending on __TypeId__ header.

WHY? We are migrating from IBM MQ to RabbitMQ. Currently, it works like that:

@JmsListener(destination = "${jms.topic})
public void receiveMessage(@NonNull Message<Object> message) {
    Object payload = message.getPayload();>     
    processByType(payload); 
}  

I'd like to have that something like that:

 @RabbitListener(queues = "${queue-name}", messageConverter = "myMessageConverter")
 public void receiveMessage(@Payload Object payload) { 
    // use existing logic 
    processByType(payload);
}

But in the case from above, it passes the object of type Message with all its details.

I found information that the method should have one parameter of a certain type (e.g.: MyPayload). and it works.

 @RabbitListener(queues = "${queue-name}", messageConverter = "myMessageConverter")
 public void receiveMessage(@Payload MyPayload payload) { ... }

It even works for message types inherited from a common interface, e.g., MyInboundPayload.

 @RabbitListener(queues = "${queue-name}", messageConverter = "myMessageConverter")
 public void receiveMessage(@Payload MyInboundPayload payload) { ... }

And I'd go with this option, but half of the payload types are library classes imported from other services. And I'm unable to make them implement MyInboundPayload.


So, does anyone know how to force it to pass an already converted message to the method? Is that possible?

public void receiveMessage(@Payload Object payload)

Thanks!


Current configuration:

    @Bean
    public MessageConverter myMessageConverter() {
        ObjectMapper objectMapper = new ObjectMapper()
                .registerModule(new JavaTimeModule())
                .registerModule(new ParanamerModule())
                .registerModule(new SingleArgConstructorModule("com.xyz.api"))
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        return new Jackson2JsonMessageConverter(objectMapper);
    }

p.s. I know that I can process Message and then get type and manually convert to a type. But I wonder if there is a way to make with @RabbitListener capabilities.

Share Improve this question edited Mar 31 at 14:21 PavloK asked Mar 31 at 13:42 PavloKPavloK 235 bronze badges 2
  • What does your configuration look like? What does your myMessageConverter do compared to the default ones? The default one you can "enforce" to use the __TYPE_ID__ header to do the deserialization, but without knowing what your myMessageConverter is that is going to be impossible to determine if that is feasible. – M. Deinum Commented Mar 31 at 14:01
  • @M.Deinum Thanks for your question, I added "Current configuration". It is Jackson2JsonMessageConverter with some settings, similarly to what was used for JmsListener. – PavloK Commented Mar 31 at 14:24
Add a comment  | 

1 Answer 1

Reset to default 1

Configure your Jackson2JsonMessageConverter to use the header to determine the type instead of the default to look at the method signature. See the javadoc for more information.

That being said your configuration is almost there, you are just missing the setting of the typePrecedence property. Default it points to INFERRED which means look at the method argument, but you can set it to TYPE_ID to force it to use the header.

@Bean
public MessageConverter myMessageConverter() {
  ObjectMapper objectMapper = new ObjectMapper()
    .registerModule(new JavaTimeModule())
    .registerModule(new ParanamerModule())
    .registerModule(new SingleArgConstructorModule("com.xyz.api"))
    .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
  var converter = new Jackson2JsonMessageConverter(objectMapper);
  converter.setTypePrecedence(TypePrecedence.TYPE_ID);
  return converter;
}

This configuration change will make it look at the header before looking at the type. So now you should be able to specify @Payload Object and get the actual type.

See comment from Artem Bilan about the security restrictions (CVE-2017-4995).

You would need to pass the possible packages to the configuration as well.

var converter = new Jackson2JsonMessageConverter(objectMapper);
converter.setTypePrecedence(TypePrecedence.TYPE_ID);
converter.setTrustedPackages("com.yourpackage.sub1", "com.yourpackage.sub2"); 
return converter;

If you don't do this you will get an exception from Jackson about the class not being allowed.

发布评论

评论列表(0)

  1. 暂无评论