我已经解决这个问题一段时间了。
1st您可以使用Map<String, Object> 反序列化您的json。它总是有效的;你得到标准类型(你的枚举将被读取为纯字符串)。
2nd 一般情况下,您始终知道您阅读的对象类型。这是顶级对象,您可以将其设置为 Jackson 映射器:mapper.readerFor(cls).readValue(json)。如果您的枚举是这个 cls 对象的一部分,那么 Jackson 知道类型并且只需读取值并对其进行解析。
3rd 实际上,一个 json 字符串可以有多个对象。我说的是继承。您可以查看 Jackson 文档中的 @JsonTypeInfo。
4th 想象一下,您阅读了一个 json 源代码,但不知道您阅读的是什么。在这种情况下,您可以要求杰克逊在对象的开头写标记。就像您询问班级名称一样。我认为它与@JsonRootName 有关。你可以看这里:Jackson JSON Deserialization with Root Element
我认为现在如何在 Jackson 中处理对象已经很清楚了。我的意思是我们知道如何告诉杰克逊我们想要反序列化什么元素。现在我们有一个问题:如何序列化 json -> 我们的枚举。
5th这不是问题,而且开箱即用。 Jackson 使用name() 方法对枚举进行序列化,使用valueOf() 进行反序列化。您可以在杰克逊的EnumDeserializer 中仔细查看。
6th 我不喜欢这种行为,因为它区分大小写。我遇到了当人们手动编写json字符串时,使用小写并且无法反序列化它的情况。此外,我相信,将枚举常量直接写入 json 文件是一种不好的做法,因为如果我想重构枚举的名称,所有存在的 json 字符串也应该修改(brrr)。为了解决这些问题,我做了以下技巧:
1. 使用parseId(String id) 的默认实现实现EnumId 接口,使用getId() 识别枚举常量并使用忽略大小写进行比较。
1.我在枚举中添加id字段
2.添加getId() - 用于序列化
3.添加parseId(String id) - 用于反序列化
4. 使用我的客户序列化程序在 Jackson ObjectMapper 添加新模块(它
should use `getId()` instead of `name()`).
if (enumId != null) {
generator.writeString(enumId.getId());
}
- 并告诉杰克逊如何反序列化这个枚举。这是一个困难的情况,因为在不同的来源中,Jackson 使用不同的反序列化层次结构,并且只是将另一个模块添加到具有自定义反序列化的 ObjectMapper (就像在 4 中一样。) 不会适用于所有情况。为了解决这个问题,我发现我们可以在枚举中的 parseId(String id) 方法中添加
@JsonCreator,Jackson 将在所有情况下使用它。
我认为这就是这个主题的全部内容。我给你一个代码示例,让你更清楚(最好写一次,然后解释两次):
public interface EnumId {
String name();
default String getId() {
return name().toLowerCase();
}
static <T extends Enum<?> & EnumId> T parseId(Class<T> cls, String id) {
T res = parseId(cls.getEnumConstants(), id, null);
if (res != null) {
return res;
}
throw new EnumConstantNotPresentException(cls, id);
}
static <T extends EnumId> T parseId(T[] values, String id, T def) {
for (T value : values) {
if (id != null ? id.equalsIgnoreCase(value.getId()) : value.getId() == null) {
return value;
}
}
return def;
}
static <T extends EnumId> T get(T value, T def) {
return value != null ? value : def;
}
}
public enum TipusViatge implements EnumId {
OCI,
NEGOCIS,
FAMILIA;
@JsonCreator
public static TipusViatge parseId(String id) {
return EnumId.parseId(TipusViatge.class, id);
}
}