如何在 MappingJackson2MessageConverter 中设置 typeIdPropertyName
How to set typeIdPropertyName in MappingJackson2MessageConverter
使用 Spring4 + ActiveMQ
我想从队列接收 JMS 消息并自动转换为 POJO。我将 MappingJackson2MessageConverter
添加到 DefaultJmsListenerContainerFactory
:
@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
// some other config
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
converter.setTypeIdPropertyName("???");
factory.setMessageConverter(converter);
return factory;
}
这是我的监听器配置
@JmsListener(destination = "queue.fas.flight.order", containerFactory = "jmsListenerContainerFactory")
public void processOrder(OrderRegisterDto registerParam) {
System.out.println(registerParam.toString());
}
我的问题是,如何设置TypeIdPropertyName
?队列不在我的控制之下;其他人发送 JSON
给它。
我想要一个 通用转换器 所以我正在使用 String
接收消息并手动将其转换为 POJO。
@JmsListener(destination = "xxxx", containerFactory = "xxxxx")
public void order(String registerParam) {
try{
OrderRegisterDto dto = objectMapper.readValue(registerParam,OrderRegisterDto.class);
}catch (IOException e){
// TODO
}
}
还有其他更好的方法吗?
转换器希望发送方在消息中为转换提供类型信息属性。
String typeId = message.getStringProperty(this.typeIdPropertyName);
typeId 可以是 class 名称,也可以是 typeId 映射图中条目的键。
如果您的消息不包含任何类型信息,您需要子class 转换器并覆盖 getJavaTypeForMessage()
到 return 杰克逊 JavaType
作为目标 class,例如:
return TypeFactory.defaultInstance().constructType(Foo.class);
如果它是一个常量并且不依赖于消息中的某些信息,您可以在子class中创建一个静态字段。
这项工作:
@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setConcurrency("3-10");
// Este es el convertidor por defeto de Spring.
SimpleMessageConverter s = new SimpleMessageConverter();
MappingJackson2MessageConverter s2 = new MappingJackson2MessageConverter();
s2.setTargetType(MessageType.BYTES);
s2.setTypeIdPropertyName("DocumentType");
factory.setMessageConverter(s2); // or "s"
return factory;
}
这是监听器:
@JmsListener(containerFactory = "jmsListenerContainerFactory", destination = ORDER_QUEUE)
@Payload final ) {
public void receiveMessage(Session ses, @Payload final Message<Product> message, @Headers final Map<String, Object> headers) {
}
以及 Java脚本 STOMP 客户端:
var product = {
productId : "111",
name : "laptop",
quantity: 2
}
var beforeSend = JSON.stringify(product);
stompClient.send(destinationProductProd_02,{"DocumentType":"org.jms.model.Product"}, beforeSend); // OK
请注意,我将 "DocumentType" STOMP header 添加到要发送的消息中。您需要发送 Java class.
的完整包路径
看起来没有简单的解决方案可以在消息中没有 "type header" 的情况下自动将 @JmsListener 中的 JSON 转换为 POJO。但是可以使用 Jackson 的 ObjectMapper 在您的代码中明确地做到这一点:
@Autowired
private ObjectMapper objectMapper;
@JmsListener(destination = "...", containerFactory = "...")
public void processOrder(String payload) {
OrderRegisterDto dto = objectMapper.readValue(payload, OrderRegisterDto.class);
System.out.println(dto.toString());
}
不要忘记在您的配置中删除 MappingJackson2MessageConverter:
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
factory.setMessageConverter(converter);
Jackson 需要类型信息才能将 JSON 转换为 POJO;
使用 @JsonTypeInfo
可以在 JSON 中自动生成 class 类型信息
所以我用这种方式解决了这个问题:
- 用
@JsonTypeInfo
定义摘要 class
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "@class")
public abstract class AbstractMessage implements Serializable {
}
- 定义 POJO 扩展
AbstractMessage
public class Xxx extends AbstractMessage {
// some properties
}
- 配置 MessageConverter
@Bean
public MessageConverter messageConverter() {
MappingJackson2MessageConverter messageConverter = new MappingJackson2MessageConverter();
messageConverter.setObjectMapper(objectMapper);
// same with @JsonTypeInfo( property )
messageConverter.setTypeIdPropertyName("@class");
return messageConverter;
}
使用 Spring4 + ActiveMQ
我想从队列接收 JMS 消息并自动转换为 POJO。我将 MappingJackson2MessageConverter
添加到 DefaultJmsListenerContainerFactory
:
@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
// some other config
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
converter.setTypeIdPropertyName("???");
factory.setMessageConverter(converter);
return factory;
}
这是我的监听器配置
@JmsListener(destination = "queue.fas.flight.order", containerFactory = "jmsListenerContainerFactory")
public void processOrder(OrderRegisterDto registerParam) {
System.out.println(registerParam.toString());
}
我的问题是,如何设置TypeIdPropertyName
?队列不在我的控制之下;其他人发送 JSON
给它。
我想要一个 通用转换器 所以我正在使用 String
接收消息并手动将其转换为 POJO。
@JmsListener(destination = "xxxx", containerFactory = "xxxxx")
public void order(String registerParam) {
try{
OrderRegisterDto dto = objectMapper.readValue(registerParam,OrderRegisterDto.class);
}catch (IOException e){
// TODO
}
}
还有其他更好的方法吗?
转换器希望发送方在消息中为转换提供类型信息属性。
String typeId = message.getStringProperty(this.typeIdPropertyName);
typeId 可以是 class 名称,也可以是 typeId 映射图中条目的键。
如果您的消息不包含任何类型信息,您需要子class 转换器并覆盖 getJavaTypeForMessage()
到 return 杰克逊 JavaType
作为目标 class,例如:
return TypeFactory.defaultInstance().constructType(Foo.class);
如果它是一个常量并且不依赖于消息中的某些信息,您可以在子class中创建一个静态字段。
这项工作:
@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setConcurrency("3-10");
// Este es el convertidor por defeto de Spring.
SimpleMessageConverter s = new SimpleMessageConverter();
MappingJackson2MessageConverter s2 = new MappingJackson2MessageConverter();
s2.setTargetType(MessageType.BYTES);
s2.setTypeIdPropertyName("DocumentType");
factory.setMessageConverter(s2); // or "s"
return factory;
}
这是监听器:
@JmsListener(containerFactory = "jmsListenerContainerFactory", destination = ORDER_QUEUE)
@Payload final ) {
public void receiveMessage(Session ses, @Payload final Message<Product> message, @Headers final Map<String, Object> headers) {
}
以及 Java脚本 STOMP 客户端:
var product = {
productId : "111",
name : "laptop",
quantity: 2
}
var beforeSend = JSON.stringify(product);
stompClient.send(destinationProductProd_02,{"DocumentType":"org.jms.model.Product"}, beforeSend); // OK
请注意,我将 "DocumentType" STOMP header 添加到要发送的消息中。您需要发送 Java class.
的完整包路径看起来没有简单的解决方案可以在消息中没有 "type header" 的情况下自动将 @JmsListener 中的 JSON 转换为 POJO。但是可以使用 Jackson 的 ObjectMapper 在您的代码中明确地做到这一点:
@Autowired
private ObjectMapper objectMapper;
@JmsListener(destination = "...", containerFactory = "...")
public void processOrder(String payload) {
OrderRegisterDto dto = objectMapper.readValue(payload, OrderRegisterDto.class);
System.out.println(dto.toString());
}
不要忘记在您的配置中删除 MappingJackson2MessageConverter:
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();factory.setMessageConverter(converter);
Jackson 需要类型信息才能将 JSON 转换为 POJO;
使用 @JsonTypeInfo
可以在 JSON 中自动生成 class 类型信息
所以我用这种方式解决了这个问题:
- 用
@JsonTypeInfo
定义摘要 class
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "@class")
public abstract class AbstractMessage implements Serializable {
}
- 定义 POJO 扩展
AbstractMessage
public class Xxx extends AbstractMessage {
// some properties
}
- 配置 MessageConverter
@Bean
public MessageConverter messageConverter() {
MappingJackson2MessageConverter messageConverter = new MappingJackson2MessageConverter();
messageConverter.setObjectMapper(objectMapper);
// same with @JsonTypeInfo( property )
messageConverter.setTypeIdPropertyName("@class");
return messageConverter;
}