假设我们有一个类
InstantMessage
,它有一个抽象子类 IMContent content
。
public class InstantMessage {
// other fields
private MessageType type;
private IMContent content;
}
public enum MessageType {
TEXT, IMAGE, VIDEO, PRODUCT, SHOPPING_ORDER, SYSTEM;
}
public abstract class IMContent {
public abstract String toText();
}
IMContent
有很多实现,比如IMTextContent
、IMImageContent
,这取决于消息的类型。
当在
InstantMessage
和@RequestBody
中使用@RequestPart
时,Spring无法反序列化IMContent
。
我尝试了几种方法,但它们都有一些明显的缺陷。
首先,我尝试将
@JsonDeserialize(using = IMContentDeserialzer.class)
添加到 content
中,但这需要我手动反序列化除内容之外的其他字段,这在添加另一个字段时非常不方便且容易忘记。我可以接受手动编写 IMContent
的反序列化,但不是整个 InstantMessage
。我希望有一种简单的方法来反序列化“非内容”字段。
我的第二次尝试是使用
@JsonTypeInfo
和@JsonSubTypes
,但这似乎需要我将type
从InstantMessage
移动到IMContent
。当我需要直接从type
访问InstantMessage
或者直接访问文本内容时也很不方便。例如,如果我需要搜索文本内容,我需要将内容展平为数据库中的字符串,当我从数据库中获取 InstantMessage
时,我需要再次类似于内容。
我也有一些解决方法,比如使用
Map
而不是 IMContent
,或者动态地将内容反序列化为 IMContent
,或者使 InstantMessage
抽象,但我认为它们并不优雅。
在这种情况下解决这个问题最简单的方法是什么?
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type",
visible = true
)
@JsonSubTypes({
@JsonSubTypes.Type(value = IMTextContent.class, name = "TEXT"),
@JsonSubTypes.Type(value = IMImageContent.class, name = "IMAGE"),
@JsonSubTypes.Type(value = IMProductContent.class, name = "PRODUCT"),
@JsonSubTypes.Type(value = IMShoppingOrderContent.class, name = "SHOPPING_ORDER"),
})
public abstract class IMContent {
public abstract String toText();
}
您是否考虑过创建自定义 Spring converter。这是一个草稿示例。
@Component
public class IMContentConverter implements Converter<String, IMContent> { //Now the endpoint should receive IMContent as body instead of InstantMessage
@Autowired
private ObjectMapper objectMapper;
public IMContent convert(String source) {
return objectMapper.readValue(source, IMContent.class);
}
}