无法将类型的对象转换为 JMS 消息。支持的消息负载有:字符串、字节数组、Map<String,?>、Serializable object
Cannot convert object of type to JMS message. Supported message payloads are: String, byte array, Map<String,?>, Serializable object
我正在开发 Spring + ActiveMQ + JMS 示例。在此示例中,我遇到以下错误:我尝试了很多选项但根本不起作用。
我希望实现以下内容:
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.createMessage(JmsTemplate.java:651)
at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:593)
at org.springframework.jms.core.JmsTemplate.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;
}
}
JMS 将数据移动到不同的 JVM。不能用普通的物体来完成。必须序列化,所以需要实现接口Serializable
假设这样可以做到,问主架构师
import java.io.Serializable;
...
public class InstructionMessage implements Serializable {
private static final long serialVersionUID = 7526472295622776147L;
....
}
背景:网络不理解Java对象,只能传输字节。
是 Java 开发的基础,任何书籍都会有所帮助(Eckel 在 Java 中的思考)
编辑:对您更改(Serializable
)代码的部分回答(尝试回答)。
现在 ClassCastException
例外说:发送和接收部分相互不兼容。
框架或服务器进行了转换 InstructionMessage -> HashMap,我猜是在早期阶段。
我猜也是,但在这里我几乎可以肯定,HashMap 内容在功能上是相同的。
最简单但不优雅的方法是保留 InstructionMessage 并在两侧使用 HashMap(更改发件人),或者调试问题。
如果我记得,您删除了转换器 class java,但保留在 XML 中。我不是 Spring 的忠实粉丝(个人讨厌 "xml programming"),我想 XML 中的一些修正可以帮助
只需添加生成的序列版本 ID,而不是默认的 1L!
public class InstructionMessage implements Serializable{
private static final long serialVersionUID = -295422703255886286L;
更新:
1)
为了使您的侦听器正常工作,您需要更新 destination="messageQueue1 因为使用 messageDestination 容器创建此队列并且您的消息被发送到 消息队列1:
<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;
}
}
改为使用 Jackson 转换,在需要触发多个事件对象的事件驱动系统中很方便
@Bean
public JmsTemplate jmsTemplate() {
JmsTemplate template = new JmsTemplate();
template.setConnectionFactory(connectionFactory());
template.setMessageConverter(jacksonJmsMessageConverter());
template.setPubSubDomain(true);
return template;
}
@Bean
public MessageConverter jacksonJmsMessageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
converter.setTypeIdPropertyName("_type");
return converter;
}
然后设置
containerFactory.setMessageConverter(jacksonJmsMessageConverter());
就是这样。
我正在开发 Spring + ActiveMQ + JMS 示例。在此示例中,我遇到以下错误:我尝试了很多选项但根本不起作用。
我希望实现以下内容:
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.createMessage(JmsTemplate.java:651)
at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:593)
at org.springframework.jms.core.JmsTemplate.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;
}
}
JMS 将数据移动到不同的 JVM。不能用普通的物体来完成。必须序列化,所以需要实现接口Serializable 假设这样可以做到,问主架构师
import java.io.Serializable;
...
public class InstructionMessage implements Serializable {
private static final long serialVersionUID = 7526472295622776147L;
....
}
背景:网络不理解Java对象,只能传输字节。 是 Java 开发的基础,任何书籍都会有所帮助(Eckel 在 Java 中的思考)
编辑:对您更改(Serializable
)代码的部分回答(尝试回答)。
现在 ClassCastException
例外说:发送和接收部分相互不兼容。
框架或服务器进行了转换 InstructionMessage -> HashMap,我猜是在早期阶段。
我猜也是,但在这里我几乎可以肯定,HashMap 内容在功能上是相同的。
最简单但不优雅的方法是保留 InstructionMessage 并在两侧使用 HashMap(更改发件人),或者调试问题。
如果我记得,您删除了转换器 class java,但保留在 XML 中。我不是 Spring 的忠实粉丝(个人讨厌 "xml programming"),我想 XML 中的一些修正可以帮助
只需添加生成的序列版本 ID,而不是默认的 1L!
public class InstructionMessage implements Serializable{
private static final long serialVersionUID = -295422703255886286L;
更新:
1) 为了使您的侦听器正常工作,您需要更新 destination="messageQueue1 因为使用 messageDestination 容器创建此队列并且您的消息被发送到 消息队列1:
<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;
}
}
改为使用 Jackson 转换,在需要触发多个事件对象的事件驱动系统中很方便
@Bean
public JmsTemplate jmsTemplate() {
JmsTemplate template = new JmsTemplate();
template.setConnectionFactory(connectionFactory());
template.setMessageConverter(jacksonJmsMessageConverter());
template.setPubSubDomain(true);
return template;
}
@Bean
public MessageConverter jacksonJmsMessageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
converter.setTypeIdPropertyName("_type");
return converter;
}
然后设置
containerFactory.setMessageConverter(jacksonJmsMessageConverter());
就是这样。