杰克逊:将枚举类型序列化为接口

3
(免责声明:极度简化。实际情况要复杂得多。)
假设我有两个系统,一个是生产者(Producer),一个是消费者(Consumer)。它们的代码完全独立,除了共享一个接口:
public interface Thing {
    String getName();
    String getDescription();
    int getPrice();
}

理念是,生产者创建一堆数据并将其作为JSON通过HTTP发送。 生产者拥有Thing的各种实现,每个实现都有附加的元数据和在数据生成过程中所需的其他内容。
由于不希望生产者除了非常薄的层外具有任何关于Jackson /序列化的知识,因此应该将序列化属性保留在Thing实现之外。 由于未来可能增加的实现数量非常大,因此为所有实现制作mixin将迅速变得难以维护。 因此,认为仅对Thing接口本身应用注释就足够了。
第一个简单的方法是在接口上使用@JsonSerialize注释。 首先看起来似乎可以工作,但结果出现了问题。 Thing的某些实现是枚举类型,导致Jackson将它们简单地序列化为其名称,而不是在接口中定义的字段。
通过一些搜索,发现了以下注释:
@JsonFormat(shape= JsonFormat.Shape.OBJECT)

虽然通过序列化字段而非名称确实解决了问题,但它过度地将实现特定的公共字段(未在Thing接口中定义)也进行了序列化,导致信息泄露以及包含未知条目的数据在Consumer中无法反序列化。由于进一步搜索没有产生任何结果,我想到的唯一解决方案是将所有这些字段标记为可忽略的,这是极不希望的,因为前面提到的原因。
是否有一种方式,仅通过更改界面本身及其注释,来强制执行确切的那些字段,既不多也不少,应该在类和枚举中序列化?

你不能只使用普通的类而不使用枚举吗? - reverse_engineer
@reverse_engineer 理论上是可以的。然而,将其中一些实现作为枚举大大简化了生产者的工作,出于某些原因我不想深入讨论。用类替换它们并不是一个真正的选择。 - BambooleanLogic
你可能仍然需要使用@JsonFormat,但是https://fasterxml.github.io/jackson-databind/javadoc/2.5/com/fasterxml/jackson/databind/ObjectMapper.html#writerFor(java.lang.Class)是另一种指定序列化类型的方式,可能会起作用。例如,mapper.writerFor(Thing.class).writeValue... - Dan
2个回答

1
我在使用Jackson时遇到了一个问题。反序列化失败,因为在反序列化过程中,Jackson无法找到多态引用类型。
你应该使用@JsonTypeInfo注释你的接口。
类似这样:

@JsonTypeInfo
public interface YourInterface {
// your code here
}

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

你的问题中没有太多的代码,因此我的回答也就很简单。


多态在这种情况下不是问题。消费者不关心类最初是什么;它只是将数据反序列化为实现Thing接口的通用bean类。问题在于它序列化了太多,而不是太少。 - BambooleanLogic

0
通常你可以强制使用特定类型,方法为:

 @JsonSerialize(as=Thing.class)

同样地,使用@JsonDeserialize也是一样的。 这对枚举类型不起作用吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接