【问题标题】:Jackson: Serializing enums as interfacesJackson:将枚举序列化为接口
【发布时间】:2013-05-08 14:41:46
【问题描述】:

(免责声明:过于简单化。实际情况要复杂得多。)

假设我有两个系统,生产者和消费者。他们的代码是完全独立的,除了一个共享接口:

public interface Thing {
    String getName();
    String getDescription();
    int getPrice();
}

这个想法是生产者创建一堆数据并通过 HTTP 将其作为 JSON 发送。 Producer 有一堆 Thing 的实现,每一个都有额外的元数据和数据生成过程所需的东西。

由于 Producer 不希望拥有任何关于 Jackson/序列化的知识,除了最顶层的薄层之外,序列化属性应该被排除在 Thing 实现之外。由于未来实施的数量很可能会增长,因此为所有这些实施混合很快就会变得不可持续。将注释应用到 Thing 接口本身就足够了。

第一个简单的方法是在接口上添加@JsonSerialize 注解。起初,这似乎可行,但导致了一个问题。 Thing 的一些实现是枚举,导致 Jackson 只是将它们序列化为它们的名称,而不是接口中定义的字段。

一些谷歌搜索显示以下注释:

@JsonFormat(shape= JsonFormat.Shape.OBJECT)

虽然它确实通过序列化字段而不是名称来解决问题,但它做得很好,因为它还开始序列化未在 Thing 接口中定义的特定于实现的公共字段,结果不仅是信息泄露,还有Consumer反序列化失败,因为数据包含未知条目。

由于进一步的谷歌搜索没有产生任何结果,我能想到的唯一解决方案是将所有这些字段标记为可忽略,由于前面提到的原因,这是非常不可取的。

有没有什么办法,只要改变接口本身和它的注释,就可以强制那些字段在涉及到类和枚举时都应该被序列化,不多也不少?

【问题讨论】:

  • 你不能不使用枚举而使用普通类吗?
  • @reverse_engineer 理论上是的。但是,将一些实现作为枚举极大地简化了 Producer,原因有多种,我不会详细介绍。用类替换它们并不是一个真正的选择。
  • 您可能仍需要@JsonFormat,但fasterxml.github.io/jackson-databind/javadoc/2.5/com/fasterxml/… 是另一种指示可能有效的序列化类型的方法。比如mapper.writerFor(Thing.class).writeValue...

标签: java json serialization jackson


【解决方案1】:

我在与 Jackson 合作时遇到了这个问题。反序列化失败是因为在反序列化过程中,Jackson 无法找到多态引用类型。

您应该使用 @JsonTypeInfo 注释您的界面。

类似:

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "class")

您的问题中没有太多代码,因此是这个答案。

【讨论】:

  • 在这种情况下多态不是问题。消费者不关心最初的类是什么;它只是将数据反序列化为实现 Thing 接口的通用类 bean 类。问题是它序列化太多,而不是太少。
【解决方案2】:

通常您应该能够通过以下方式强制使用某些类型:

 @JsonSerialize(as=Thing.class)

@JsonDeserialize 类似。 这不适用于枚举吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-16
    • 2011-12-07
    • 1970-01-01
    • 2021-12-27
    • 2015-10-19
    • 2012-02-06
    • 1970-01-01
    相关资源
    最近更新 更多