【问题标题】:Spring Boot RabbitMQ Receiver Jackson Deserialize to POJOSpring Boot RabbitMQ Receiver Jackson 反序列化为 POJO
【发布时间】:2017-08-22 21:25:18
【问题描述】:

我有一个 spring boot 项目,我正在尝试与 rabbitmq 服务器集成,以便可以向队列发布和读取消息。

这是我的 rabbitmq 配置(编辑为仅显示相关详细信息):

@Configuration
@ConfigurationProperties(prefix="rabbit")
public class RabbitConfig {
    private String queue;

    @Bean
    Queue queue() {
        return new Queue(queue, durable);
    }

    @Bean
    public MessageConverter jsonMessageConverter(){
        return new Jackson2JsonMessageConverter();
    }

    @Bean
    SimpleMessageListenerContainer container(ConnectionFactory connectionFactory, Queue queue,
                                             MessageListenerAdapter listenerAdapter, MessageConverter messageConverter) {
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
        container.setQueues(queue);
        container.setMessageListener(listenerAdapter);
        container.setMessageConverter(messageConverter);
        return container;
    }

    @Bean
    MessageListenerAdapter listenerAdapter(Receiver receiver) {
        return new MessageListenerAdapter(receiver);
    }

    public void setQueue(String queue) {
        this.queue = queue;
    }
}

这是我的接收器类:

public interface Receiver {
    void handleMessage(FooA message);
}

@Component
public class RabbitReceiver implements Receiver {
    @Override
    public void handleMessage(FooA message) {
        System.out.println(message);
    }
}

还有我的pojo:

public class FooA {}
    private double num;
    private Map<String, String> map = new HashMap();

    public FooA() {
    }

    public FooA(double num, Map<String, String> map) {
        this.num = num;
        this.map = map;
    }

    public int getnum() {
        return num;
    }

    public Map<String, String> getMap() {
        return map;
    }
}

我成功地将FooA 消息对象发布到队列。这是队列中的样子:

[
    {
        "payload_bytes": 41,
        "redelivered": false,
        "exchange": "amq.fanout",
        "routing_key": "",
        "message_count": 0,
        "properties": {
            "priority": 0,
            "delivery_mode": 2,
            "headers": {
                "__TypeId__": "com.test.FooA"
            },
            "content_encoding": "UTF-8",
            "content_type": "application/json"
        },
        "payload": "{\"num\":1.2,\"map\":{}}",
        "payload_encoding": "string"
    }
]

但是当我尝试从队列中读取时,我得到了这个错误:

org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Failed to invoke target method 'handleMessage' with argument type = [class [B], value = [{[B@75a7bfc9}]
    at org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.invokeListenerMethod(MessageListenerAdapter.java:408) ~[spring-rabbit-1.7.3.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.onMessage(MessageListenerAdapter.java:298) ~[spring-rabbit-1.7.3.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:822) ~[spring-rabbit-1.7.3.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:745) ~[spring-rabbit-1.7.3.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$001(SimpleMessageListenerContainer.java:97) [spring-rabbit-1.7.3.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$1.invokeListener(SimpleMessageListenerContainer.java:189) ~[spring-rabbit-1.7.3.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.invokeListener(SimpleMessageListenerContainer.java:1276) [spring-rabbit-1.7.3.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:726) ~[spring-rabbit-1.7.3.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:1219) [spring-rabbit-1.7.3.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:1189) [spring-rabbit-1.7.3.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1500(SimpleMessageListenerContainer.java:97) [spring-rabbit-1.7.3.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1421) [spring-rabbit-1.7.3.RELEASE.jar:na]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_121]
Caused by: java.lang.NoSuchMethodException: com.test.RabbitReceiver.handleMessage([B)
    at java.lang.Class.getMethod(Class.java:1786) ~[na:1.8.0_121]
    at org.springframework.util.MethodInvoker.prepare(MethodInvoker.java:174) ~[spring-core-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.invokeListenerMethod(MessageListenerAdapter.java:386) ~[spring-rabbit-1.7.3.RELEASE.jar:na]
    ... 12 common frames omitted

我做错了什么?

编辑1:我把方法改成:

@Override
public void handleMessage(byte[] message) {
    System.out.println(message);
}

哪个有效,但完全无法使用。它只是这样显示:

如何将其映射到我的 pojo FooA

【问题讨论】:

  • 我猜handleMessage 正在使用某个数组被调用,并且没有定义这样的方法。
  • @redflar3 是的!在上面进行了编辑

标签: java json spring jackson rabbitmq


【解决方案1】:

我刚刚让实现Serializable 接口的类删除了JsonMessageConverter。 Json 和 Serializable 是冲突的,所以它不起作用。

【讨论】:

  • 你序列化了哪个类
【解决方案2】:

将 bytearray 转换为字符串并使用 jackson mapper (ObjectMapper) 映射到您的 pojo。您的映射器上有配置:例如

 this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    this.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
    this.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
    this.registerModule(new JavaTimeModule())

【讨论】:

    【解决方案3】:

    看起来消息是作为字符串而不是 JSON 发布的。 就是这样看的

    "payload_encoding": "string"
    

    Spring 可以自动将此字符串转换为 byte[],如屏幕截图所示。

    您还需要像这样在 RabbitTemplate 上设置消息转换器:

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory,MessageConverter rabbitJsonMessageConverter) {
        RabbitTemplate template = new RabbitTemplate(connectionFactory);
        template.setMessageConverter(rabbitJsonMessageConverter);
        return template;
    }
    

    这应该正确地将消息发布为 JSON。

    【讨论】:

    • 不幸的是,当我将消息放入队列时,我的配置已经有这段模板代码,但它仍然以字符串编码的形式出现。
    【解决方案4】:

    你做的一切都是正确的。但是您没有向MessageListenerAdapter 提供任何方法来接收和处理您的消息。这就是您收到 ListenerExecutionFailedException: Failed to invoke target method 'handleMessage' 的原因。

    要修复此更改,请使用以下代码:

    @Bean
        MessageListenerAdapter listenerAdapter(Receiver receiver) {
            return new MessageListenerAdapter(receiver);
        }
    

    到:

    @Bean
        MessageListenerAdapter listenerAdapter(Receiver receiver) {
            return new MessageListenerAdapter(receiver, "handleMessage");
        }
    

    【讨论】:

      【解决方案5】:

      本文展示了如何以更简单的方式解决此问题:https://thepracticaldeveloper.com/produce-and-consume-json-messages-with-spring-boot-amqp/

      配置:

      @Bean
      public RabbitTemplate rabbitTemplate(final ConnectionFactory connectionFactory) {
          final var rabbitTemplate = new RabbitTemplate(connectionFactory);
          rabbitTemplate.setMessageConverter(producerJackson2MessageConverter());
          return rabbitTemplate;
      }
      
      @Bean
      public Jackson2JsonMessageConverter producerJackson2MessageConverter() {
          return new Jackson2JsonMessageConverter();
      }
      

      听众:

      @RabbitListener(queues = MessagingApplication.QUEUE_SPECIFIC_NAME)
      public void receiveMessage(final CustomMessage customMessage) {
          log.info("Received message and deserialized to 'CustomMessage': {}", customMessage.toString());
      }
      

      POJO:

      public record CustomMessage(@JsonProperty("text") String text,
                                  @JsonProperty("priority") int priority,
                                  @JsonProperty("secret") boolean secret)
              implements Serializable {
      }
      

      【讨论】:

        猜你喜欢
        • 2019-04-03
        • 2021-03-31
        • 1970-01-01
        • 1970-01-01
        • 2023-02-08
        • 2018-01-24
        • 1970-01-01
        • 2014-10-22
        • 2012-04-07
        相关资源
        最近更新 更多