2017-01-16 6 views
0

Я разрабатываю Spring + ActiveMQ + JMS пример. В этом примере я столкнулся с следующей ошибкой: я попробовал с многими опциями, но не работал вообще.Невозможно преобразовать объект типа в сообщение JMS. Поддерживаемые сообщения полезной нагрузки: String, массив байтов, карта <String,?>, объект Serializable

Я ищу осуществлять следующее:

1) Очередь должна поддерживать чтение сообщений (либо с помощью конвертера или слушателя)

2) на основе типа InstructionMessage я должен принять решение о том, где отправить его или нет.

Код загружен в: https://github.com/test512/spring-mvc-jms-tutorials

Sending person InstructionMessage [instructionType=10, productCode=10, quantity=10, uOM=10, timeStamp=10] 
Exception in thread "main" org.springframework.jms.support.converter.MessageConversionException: Cannot convert object of type [com.jms.testing.spring.InstructionMessage] to JMS message. Supported message payloads are: String, byte array, Map<String,?>, Serializable object. 
    at org.springframework.jms.support.converter.SimpleMessageConverter.toMessage(SimpleMessageConverter.java:78) 
    at org.springframework.jms.core.JmsTemplate$5.createMessage(JmsTemplate.java:651) 
    at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:593) 
    at org.springframework.jms.core.JmsTemplate$3.doInJms(JmsTemplate.java:562) 
    at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:484) 
    at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:559) 
    at org.springframework.jms.core.JmsTemplate.convertAndSend(JmsTemplate.java:648) 
    at org.springframework.jms.core.JmsTemplate.convertAndSend(JmsTemplate.java:639) 
    at com.jms.testing.spring.SpringJmsPersonProducer.sendMessage(SpringJmsPersonProducer.java:18) 
    at com.jms.testing.spring.SpringJmsMessageConverterExample.main(SpringJmsMessageConverterExample.java:16) 

appContextWithMessageConverter.xml

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:jms="http://www.springframework.org/schema/jms" 
    xsi:schemaLocation="http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms.xsd 
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> 

    <context:property-placeholder location="classpath:jms.properties" /> 

    <bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> 
     <property name="brokerURL" value="${jms.brokerURL}" /> 
    </bean> 

    <bean id="pooledJmsConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop"> 
     <property name="connectionFactory" ref="jmsConnectionFactory" /> 
     <property name="maxConnections" value="50" /> 
    </bean> 

    <jms:listener-container container-type="default" connection-factory="pooledJmsConnectionFactory" acknowledge="auto" > 
     <!-- <jms:listener destination="messageDestination" ref="messageDestination" /> --> 
     <jms:listener destination="messageDestination" ref="myListener" /> 
    </jms:listener-container> 

    <bean id="instructionMessageConverter" class="com.jms.testing.spring.InstructionMessageConverter" /> 

    <bean id="myListener" class="com.jms.testing.spring.MyListener" /> 

    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"> 
     <constructor-arg ref="pooledJmsConnectionFactory" /> 
     <property name="defaultDestination" ref="messageDestination" /> 
     <property name="receiveTimeout" value="${jms.receiveTimeout}" /> 
     <!-- <property name="messageConverter" ref="instructionMessageConverter" /> --> 

    </bean> 

    <bean id="springJmsPersonProducer" class="com.jms.testing.spring.SpringJmsPersonProducer"> 
     <property name="jmsTemplate" ref="jmsTemplate" /> 
    </bean> 

    <bean id="springJmsPersonConsumer" class="com.jms.testing.spring.SpringJmsPersonConsumer"> 
     <property name="jmsTemplate" ref="jmsTemplate" /> 
    </bean> 

    <bean id="messageDestination" class="org.apache.activemq.command.ActiveMQQueue"> 
     <constructor-arg value="messageQueue1" /> 
    </bean> 
</beans> 

MyListener.java

public class MyListener implements MessageListener { 

    @Override 
    public void onMessage(Message message) { 
     MapMessage mapMessage = (MapMessage) message; 

     try { 
      int instructionType = Integer.parseInt(mapMessage.getString("instructionType")); 
      int productCode = Integer.parseInt(mapMessage.getString("productCode")); 
      int quantity = Integer.parseInt(mapMessage.getString("quantity")); 
      int timeStamp = Integer.parseInt(mapMessage.getString("timeStamp")); 
      int uOM = Integer.parseInt(mapMessage.getString("uOM")); 
      InstructionMessage instructionMessage = new InstructionMessage(instructionType, productCode, quantity, uOM, 
        timeStamp); 
      System.out.println(instructionMessage.toString()); 

     } catch (NumberFormatException | JMSException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

    } 
} 

InstructionMessage.java

public class InstructionMessage implements Serializable{ 

private static final long serialVersionUID = 1L; 
    private int instructionType; 
    private int productCode; 
    private int quantity; 
    private int uOM; 
    private int timeStamp; 


    public InstructionMessage(int instructionType, int productCode, int quantity, int uOM, int timeStamp) { 
     super(); 
     this.instructionType = instructionType; 
     this.productCode = productCode; 
     this.quantity = quantity; 
     this.uOM = uOM; 
     this.timeStamp = timeStamp; 
    } 

    public int getInstructionType() { 
     return instructionType; 
    } 

    public void setInstructionType(int instructionType) { 
     this.instructionType = instructionType; 
    } 

    public int getProductCode() { 
     return productCode; 
    } 

    public void setProductCode(int productCode) { 
     this.productCode = productCode; 
    } 

    public int getQuantity() { 
     return quantity; 
    } 

    public void setQuantity(int quantity) { 
     this.quantity = quantity; 
    } 

    public int getuOM() { 
     return uOM; 
    } 

    public void setuOM(int uOM) { 
     this.uOM = uOM; 
    } 

    public int getTimeStamp() { 
     return timeStamp; 
    } 

    public void setTimeStamp(int timeStamp) { 
     this.timeStamp = timeStamp; 
    } 

    @Override 
    public String toString() { 
     return "InstructionMessage [instructionType=" + instructionType + ", productCode=" + productCode + ", quantity=" 
       + quantity + ", uOM=" + uOM + ", timeStamp=" + timeStamp + "]"; 
    } 
} 

SpringJmsMessageConverterExample.java

public class SpringJmsMessageConverterExample { 
    public static void main(String[] args) throws URISyntaxException, Exception { 
     ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
       "appContextWithMessageConverter.xml"); 

     try { 
      SpringJmsPersonProducer springJmsProducer = (SpringJmsPersonProducer) context.getBean("springJmsPersonProducer"); 
      InstructionMessage m1 = new InstructionMessage(10,10,10,10,10); 
      System.out.println("Sending person " + m1); 
      springJmsProducer.sendMessage(m1); 

      InstructionMessage m2 = new InstructionMessage(5,5,5,5,5); 
      System.out.println("Sending person " + m2); 
      springJmsProducer.sendMessage(m2); 

      InstructionMessage m3 = new InstructionMessage(0,0,0,0,0); 
      System.out.println("Sending person " + m3); 
      springJmsProducer.sendMessage(m3); 

      System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); 

      SpringJmsPersonConsumer springJmsConsumer = (SpringJmsPersonConsumer) context.getBean("springJmsPersonConsumer"); 
      System.out.println("Consumer receives " + springJmsConsumer.receiveMessage()); 
     } finally { 
      context.close(); 
     } 
    } 
} 

SpringJmsPersonProducer.java

public class SpringJmsPersonProducer { 

    private JmsTemplate jmsTemplate; 

    public JmsTemplate getJmsTemplate() { 
     return jmsTemplate; 
    } 

    public void setJmsTemplate(JmsTemplate jmsTemplate) { 
     this.jmsTemplate = jmsTemplate; 
    } 

    public void sendMessage(final InstructionMessage instructionMessage) { 
     getJmsTemplate().convertAndSend(instructionMessage); 
    } 
} 

SpringJmsPersonConsumer.java

public class SpringJmsPersonConsumer { 

    private JmsTemplate jmsTemplate; 

    public JmsTemplate getJmsTemplate() { 
     return jmsTemplate; 
    } 

    public void setJmsTemplate(JmsTemplate jmsTemplate) { 
     this.jmsTemplate = jmsTemplate; 
    } 

    public InstructionMessage receiveMessage() throws JMSException { 
     InstructionMessage instructionMessage = (InstructionMessage) getJmsTemplate().receiveAndConvert(); 
     return instructionMessage; 
    } 
} 

ответ

1

просто добавьте сгенерированный серийный идентификатор версии, а не по умолчанию 1L!

public class InstructionMessage implements Serializable{ 

private static final long serialVersionUID = -295422703255886286L; 

UPDATE:

1) , чтобы слушатель работает нормально, то вам необходимо обновить назначения = "messageQueue1, потому что с messageDestination контейнер создания этой очереди и ваши сообщения являются отправлено на адрес messageQueue1:

<jms:listener-container container-type="default" 
    connection-factory="pooledJmsConnectionFactory" acknowledge="auto"> 
    <jms:listener destination="messageQueue1" ref="myListener" /> 
</jms:listener-container> 

и обновление MyListener

import javax.jms.JMSException; 
import javax.jms.Message; 
import javax.jms.MessageListener; 
import javax.jms.ObjectMessage; 

public class MyListener implements MessageListener { 

    @Override 
    public void onMessage(Message message) { 
     try { 
      ObjectMessage mapMessage = (ObjectMessage) message; 
      InstructionMessage instructionMessage = (InstructionMessage) mapMessage.getObject(); 
      System.out.println(instructionMessage.toString()); 
     } catch (NumberFormatException | JMSException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

2) условное посыла

import org.springframework.jms.core.JmsTemplate; 

public class SpringJmsPersonProducer { 

    private JmsTemplate jmsTemplate; 

    public JmsTemplate getJmsTemplate() { 
     return jmsTemplate; 
    } 

    public void setJmsTemplate(JmsTemplate jmsTemplate) { 
     this.jmsTemplate = jmsTemplate; 
    } 

    public void sendMessage(final InstructionMessage instructionMessage) { 
     if (canSend(instructionMessage)) { 
      getJmsTemplate().convertAndSend(instructionMessage); 
     } else { 
      throw new IllegalArgumentException("message"); 
     } 
    } 

    private boolean canSend(InstructionMessage instructionMessage) { 
     return instructionMessage.getQuantity() > 0; 
    } 
} 
+0

Я протестировал ваш код github, и он отлично работает с сгенерированным серийным идентификатором версии, вы пробовали? –

+0

только сгенерирована serialVersionUID = -295422703255886286L; потому что по умолчанию у 1L у меня были исключения –

+0

вы очистили свою очередь ?? это не из-за старых сообщений? –

0

JMS перемещает данные в разные JVM. Нельзя делать с обычными объектами. Должно быть сериализовать, поэтому требуется реализовать интерфейс Serializable Предположим, например можно сделать, спросите главного архитектора

import java.io.Serializable; 
... 
public class InstructionMessage implements Serializable { 

private static final long serialVersionUID = 7526472295622776147L; 

.... 
} 

Справочная информация: сеть не понимают объекты Java, могут передавать только байты. Является базовым для разработки Java, любая книга может быть полезной (Мышление в Java от Eckel)

EDIT: частичный ответ (попробуйте ответить) вам изменился (с кодом Serializable). Теперь ClassCastException исключение говорит: отправка и прием часть взаимно несовместимы. Рамки или серверное преобразование InstructionMessage -> HashMap, я думаю, на ранних этапах.

Я тоже думаю, но здесь я почти уверен, содержимое HashMap функционально одинаково.

Ваш простой, но не элегантный способ - оставить InstructionMessage и работать с HashMap с обеих сторон (изменить отправителя) или отладить проблему.

Если я помню, вы удаляете класс конвертера java, но остаетесь в XML.Я не большой поклонник Spring (лично ненавижу «программирование xml»), я думаю, что некоторая коррекция в XML может помочь

+0

Я получаю сообщение об ошибке: 'Исключение в нити "основной" java.lang.ClassCastException: java.util.HashMap не может быть отнесено к com.jms.testing.spring.InstructionMessage \t at com.jms.testing.spring.SpringJmsPersonConsumer.receiveMessage (SpringJmsPersonConsumer.java:20) \t at com.jms.testing.spring.SpringJmsMessageConverterExample.main (SpringJmsMessageConverterExample.java:29) ' –

+0

Принимающая сторона принимает в байтах поток - это HashMap (одна из универсальных структур, способных перемещать данные, как правило, с помощью JMS), но в байтах InstructionMessage. Стороны отправки и получения несовместимы. Позвольте мне посмотреть некоторое время в коде –

+0

Эй, я загрузил свой код https://github.com/test512/spring-mvc-jms-tutorials. Вам просто нужно загрузить ActiveMQ inorder, чтобы протестировать его. Спасибо за вашу корпорацию. –