Cannot convert object of type to JMS message. Supp

2019-08-01 14:13发布

I am developing Spring + ActiveMQ + JMS example. In this example, I am facing the below error: I tried with Many options but not working at all.

I am looking to implement the following:

1) Queue should be keep reading messages (either using the Converter or listener)

2) Based on the InstructionMessage type I have to take decision on where to send it or not.

The code uploaded at : 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;  
    }
}

2条回答
贪生不怕死
2楼-- · 2019-08-01 14:27

JMS moves data to different JVM. Cannot be done with ordinary objects. Must be serialised, so require to implement interface Serializable Suppose such can be done, ask main architect

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

 private static final long serialVersionUID = 7526472295622776147L;

....
}

Background: network don't understand Java objects, can only transfer bytes. Is is basic for Java development, any book can be helpful (Thinking in Java by Eckel)

EDIT: partial answer (try to answer) to You changed (with Serializable) code. Now ClassCastException exception says: sending and receiving part are mutual not compatible. Framework or server made conversion InstructionMessage -> HashMap, I guess on early stages.

I guess too, but here I'm almost sure, HashMap content is functionally the same.

Your simplest, but not elegant way is to leave InstructionMessage and work with HashMap on both side (change sender), or debug a problem.

If I remember, You remove Converter class java, but remain in XML. I'm NOT a big Spring fan (personally hate "xml programming"), I guess some correction in XML can help

查看更多
别忘想泡老子
3楼-- · 2019-08-01 14:39

simply add a generated serial Version ID and not default 1L!

public class InstructionMessage implements Serializable{

private static final long serialVersionUID = -295422703255886286L;

UPDATE :

1) to make your listener working fine, you need to update destination="messageQueue1 because with messageDestination container create this queue and your messages are sent to messageQueue1 :

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

and update 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) conditional send

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;
    }
}
查看更多
登录 后发表回答