2017-08-22 2 views
0

J'ai un projet de démarrage de printemps où j'essaie d'intégrer un serveur rabbitmq afin que je puisse publier et lire des messages vers/depuis une file d'attente.Spring Boot RabbitMQ Récepteur Jackson Deserialize to POJO

Voilà ma config RabbitMQ (éditée à seulement voir les détails pertinents):

@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; 
    } 
} 

Voici mes classes de récepteur:

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

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

et mon 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; 
    } 
} 

Je suis réussi à publier un objet de message FooA dans la file d'attente. Voici à quoi il ressemble dans la file d'attente:

[ 
    { 
     "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" 
    } 
] 

Mais lorsque je tente de lire la file d'attente je reçois cette erreur:

org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Failed to invoke target method 'handleMessage' with argument type = [class [B], value = [{[[email protected]}] 
    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 

Qu'est-ce que je fais mal?

Edit 1: J'ai changé la méthode:

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

Ce qui a fonctionné, mais il est totalement inutilisable. Cela montre comme ça:

enter image description here

Comment puis-je obtenir ce à la carte à mon POJO FooA

+0

Je suppose que 'handleMessage' est appelé en utilisant un tableau, et une telle méthode n'est pas définie. –

+0

@ redflar3 yup! Fait un edit au dessus de – Richard

Répondre

0

Je viens d'avoir les classes implémenter l'interface Serializable retiré le JsonMessageConverter. Json et Serializable étaient en conflit donc ça n'a pas marché.

0

Il semble que le message est affiché en tant que chaîne et non comme JSON. Cest comme bon vous

"payload_encoding": "string" 

et Spring peut convertir automatiquement cette chaîne dans un octet [], comme le montre la capture d'écran.

Vous devez régler le convertisseur de message également sur le RabbitTemplate comme ceci:

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

Cela devrait publier correctement le message comme JSON.

+0

Malheureusement, ma config a déjà ce bit de code pour le template lors de la mise en file d'attente d'un message, mais il ressort comme une chaîne encodée. – Richard

0

Convertissez le bytearray en chaîne et utilisez le mappeur jackson (ObjectMapper) pour mapper sur votre pojo. Vous avez des configurations sur votre mappeur: par ex.

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())