jackson - HornetQ - 如何发送和转换 POJO

标签 jackson gson pojo hornetq

我在嵌入式模式下使用 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 正在寻找“电话”值并需要一个字符串,但它找到一个对象并崩溃。

如何解决这个问题?

还有其他选择吗?

我也尝试使用 Gson 而不是 Jackson,但它返回了相同的错误。

有趣的事实是,如果您发送一个没有任何字符串参数的对象,它可以正常工作。

(应该不是必需的,但如果您愿意的话)在这里您可以找到以下的整个类:

最佳答案

这并不是很明显,但 Jackson 在反序列化 org.hornetq.api.core.SimpleString 时失败了,而 Jackson 并不知道。 Gson 也是如此,因为 SimpleString 不是标准类。

这里有两个选择:

  • 将传入消息负载规范化为标准对象。
  • 或者实现自定义 SimpleString 序列化器/反序列化器。

选项#1:标准化

顺便说一句,Message.toMap() 也会返回消息系统属性(您在 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() 不同,这会丢弃 durableaddressmessageIDexpirationtypeprioritytimestamp 等系统属性。 因此,您需要的是 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> 通过自定义序列化 -> 一些中间表示通过内置反序列化 -> 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 类,

{phone=phone, name=name, id=13}

属性,以及类似的内容

ClientMessage[messageID=8, durable=false, address=q49589558,userID=null,properties=TypedProperties[id=13,phone=phone,name=name]]

用于客户端消息。

关于jackson - HornetQ - 如何发送和转换 POJO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49589558/

相关文章:

jackson - jackson 未能反序列化Kotlin数据类

java - 解析具有重复键的 Json

java - 如何在 Json 树中按名称查找节点?

java - 像数据仓库一样预先计算额外的 Java 对象字段还是即时计算?

java - 让 Jackson 解释单值 JSON

java - 在使用 eclipse (Kepler) 实现的 Applet 中使用 GSON 的正确配置是什么

java - 如何解决 MalformedJsonException : Unterminated object that exist even after setting JsonReader to lenient

java - 使用GSON将JSON数据转换为Java对象(包括Object类)

java - 这个类是POJO吗

java - 为我的类中使用的通用 pojo 建模