HornetQ——如何发送和转换POJO
HornetQ - how to send and convert POJO
我在嵌入式模式下使用 HornetQ。
我正在尝试从发布者向消费者发送一个 POJO 对象:
public class Pojo implements Serializable {
private Integer id;
private String name;
private String phone;
// constructors, getters & setters
}
我的想法是将 POJO 转换为 Map 并通过 ClientMessage 发送每个属性。 (这样Consumer就可以通过POJO的属性来过滤消息了)
为此,我使用了 Jackson ObjectMapper。
出版商
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> pojoMap = mapper.convertValue(new Pojo(13, "name", "phone"), new TypeReference<Map<String, Object>>() {});
pojoMap.forEach(message::putObjectProperty);
producer.send(message);
消费者
consumer.setMessageHandler(message -> {
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
Pojo pojo = mapper.convertValue(mapJson, Pojo.class);
});
问题是在反序列化(在 Consumer 中)期间 ObjectMapper 抛出异常:
java.lang.IllegalArgumentException: Cannot deserialize instance of 'java.lang.String' out of START_OBJECT token
at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: org.hornetq.core.example.Pojo["phone"])
...
据我了解,ObjectMapper 正在寻找 'phone' 值并想要一个字符串,但它找到了一个对象并崩溃了。
我该如何解决这个问题?
有其他选择吗?
我也尝试过使用 Gson 而不是 Jackson,但它 returns 我遇到了同样的错误。
有趣的是,如果您发送一个没有任何字符串参数的对象,它可以正常工作。
(应该不是必需的,但如果你愿意的话)在这里你可以找到整个 类 of:
这不是很明显,但 Jackson 在反序列化 org.hornetq.api.core.SimpleString
时失败了,Jackson 并不知道。
Gson 也是如此,因为 SimpleString
不是标准 class.
这里有两个选择:
- 要么将传入消息有效负载规范化为标准对象。
- 或实施自定义
SimpleString
serializer/deserializer.
选项 #1:规范化
顺便说一下,Message.toMap()
returns 消息系统属性(您在 PasteBin 中的代码似乎使用了它),因此它们可能会与您的自定义对象属性发生冲突(我不使用HornetQ 所以我可以使用错误的术语)。
我相信,属性应该像这样规范化:
public static Map<String, Object> getNormalizedPropertiesFrom(final Message message) {
return message.getPropertyNames()
.stream()
.collect(Collectors.toMap(
SimpleString::toString,
simpleString -> {
final Object objectProperty = message.getObjectProperty(simpleString);
if ( objectProperty instanceof SimpleString ) {
return objectProperty.toString();
}
return objectProperty;
}
));
}
这与 Message.toMap()
不同,它将丢弃 durable
、address
、messageID
、expiration
、type
、priority
和 timestamp
。
所以,你需要的是 mapper.convertValue(getNormalizedPropertiesFrom(message), Pojo.class)
.
选项 #2:自定义(反)序列化
在这种情况下,您可以简化属性提取
public static Map<SimpleString, Object> getPropertiesFrom(final Message message) {
return message.getPropertyNames()
.stream()
.collect(Collectors.toMap(Function.identity(), message::getObjectProperty));
}
但是您的 ObjectMapper
实例必须知道 SimpleString
是如何(反)序列化的。
请注意,ObjectMapper.convertValue()
(我相信)在转换时使用中间对象,它需要一个用于此场景的序列化程序(Message
-> Map<SimpleString, Object>
通过自定义序列化 -> 一些中间表示 通过 built-in 反序列化 -> Pojo
).
final ObjectMapper objectMapper = new ObjectMapper()
.registerModule(new SimpleModule()
.addSerializer(SimpleString.class, new JsonSerializer<SimpleString>() {
@Override
public void serialize(@Nonnull final SimpleString simpleString, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider)
throws IOException {
jsonGenerator.writeString(simpleString.toString());
}
})
)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
出于性能原因,您应该使用单个 ObjectMapper
实例。
两个选项都会产生:
Pojo{id=13, name=name, phone=phone}
为 Pojo
class,
{phone=phone, name=name, id=13}
对于属性,以及诸如
ClientMessage[messageID=8, durable=false, address=q49589558,userID=null,properties=TypedProperties[id=13,phone=phone,name=name]]
客户端消息。
我在嵌入式模式下使用 HornetQ。
我正在尝试从发布者向消费者发送一个 POJO 对象:
public class Pojo implements Serializable {
private Integer id;
private String name;
private String phone;
// constructors, getters & setters
}
我的想法是将 POJO 转换为 Map 并通过 ClientMessage 发送每个属性。 (这样Consumer就可以通过POJO的属性来过滤消息了)
为此,我使用了 Jackson ObjectMapper。
出版商
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> pojoMap = mapper.convertValue(new Pojo(13, "name", "phone"), new TypeReference<Map<String, Object>>() {});
pojoMap.forEach(message::putObjectProperty);
producer.send(message);
消费者
consumer.setMessageHandler(message -> {
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
Pojo pojo = mapper.convertValue(mapJson, Pojo.class);
});
问题是在反序列化(在 Consumer 中)期间 ObjectMapper 抛出异常:
java.lang.IllegalArgumentException: Cannot deserialize instance of 'java.lang.String' out of START_OBJECT token
at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: org.hornetq.core.example.Pojo["phone"])
...
据我了解,ObjectMapper 正在寻找 'phone' 值并想要一个字符串,但它找到了一个对象并崩溃了。
我该如何解决这个问题?
有其他选择吗?
我也尝试过使用 Gson 而不是 Jackson,但它 returns 我遇到了同样的错误。
有趣的是,如果您发送一个没有任何字符串参数的对象,它可以正常工作。
(应该不是必需的,但如果你愿意的话)在这里你可以找到整个 类 of:
这不是很明显,但 Jackson 在反序列化 org.hornetq.api.core.SimpleString
时失败了,Jackson 并不知道。
Gson 也是如此,因为 SimpleString
不是标准 class.
这里有两个选择:
- 要么将传入消息有效负载规范化为标准对象。
- 或实施自定义
SimpleString
serializer/deserializer.
选项 #1:规范化
顺便说一下,Message.toMap()
returns 消息系统属性(您在 PasteBin 中的代码似乎使用了它),因此它们可能会与您的自定义对象属性发生冲突(我不使用HornetQ 所以我可以使用错误的术语)。
我相信,属性应该像这样规范化:
public static Map<String, Object> getNormalizedPropertiesFrom(final Message message) {
return message.getPropertyNames()
.stream()
.collect(Collectors.toMap(
SimpleString::toString,
simpleString -> {
final Object objectProperty = message.getObjectProperty(simpleString);
if ( objectProperty instanceof SimpleString ) {
return objectProperty.toString();
}
return objectProperty;
}
));
}
这与 Message.toMap()
不同,它将丢弃 durable
、address
、messageID
、expiration
、type
、priority
和 timestamp
。
所以,你需要的是 mapper.convertValue(getNormalizedPropertiesFrom(message), Pojo.class)
.
选项 #2:自定义(反)序列化
在这种情况下,您可以简化属性提取
public static Map<SimpleString, Object> getPropertiesFrom(final Message message) {
return message.getPropertyNames()
.stream()
.collect(Collectors.toMap(Function.identity(), message::getObjectProperty));
}
但是您的 ObjectMapper
实例必须知道 SimpleString
是如何(反)序列化的。
请注意,ObjectMapper.convertValue()
(我相信)在转换时使用中间对象,它需要一个用于此场景的序列化程序(Message
-> Map<SimpleString, Object>
通过自定义序列化 -> 一些中间表示 通过 built-in 反序列化 -> Pojo
).
final ObjectMapper objectMapper = new ObjectMapper()
.registerModule(new SimpleModule()
.addSerializer(SimpleString.class, new JsonSerializer<SimpleString>() {
@Override
public void serialize(@Nonnull final SimpleString simpleString, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider)
throws IOException {
jsonGenerator.writeString(simpleString.toString());
}
})
)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
出于性能原因,您应该使用单个 ObjectMapper
实例。
两个选项都会产生:
Pojo{id=13, name=name, phone=phone}
为 Pojo
class,
{phone=phone, name=name, id=13}
对于属性,以及诸如
ClientMessage[messageID=8, durable=false, address=q49589558,userID=null,properties=TypedProperties[id=13,phone=phone,name=name]]
客户端消息。