杰克逊反序列化具有多个名称的枚举
Jackson deserialize Enums with multiple names
我在反序列化具有多个值名称的枚举时遇到问题。下面是一个示例:Info 是一个 Java class,里面有一个具有多个名称的枚举:
public class Info {
//...
private ContainerFormat format;
}
// ContainerFormat.java:
public enum ContainerFormat {
// ....
MP4("mp4", "mpeg4"),
UNKNOWN("null");
private String name;
private List<String> others;
ContainerFormat(String name) {
this.name = name;
}
/** The service does not always return the same String for output formats.
* This 'other' string fixes the deserialization issues caused by that.
*/
ContainerFormat(String name, String... others) {
this.name = name;
this.others = new ArrayList<String>();
for (String other : others) {
this.others.add(other);
}
}
@JsonValue
@Override
public String toString() {
return name;
}
public List<String> otherNames() {
return others;
}
@JsonCreator
public static ContainerFormat fromValue(String other) throws JsonMappingException {
for (ContainerFormat format : ContainerFormat.values()) {
if (format.toString().equalsIgnoreCase(other)) {
return format;
}
if (format.otherNames() != null && format.otherNames().contains(other)) {
return format;
}
}
return UNKNOWN;
}
}
问题是当我反序列化包含 "mpeg4" 而不是 mp4 的内容时出现此错误:
com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not construct instance of com.foo.ContainerFormat from String value 'mpeg4': value not one of declared Enum instance names
at [Source: N/A; line: -1, column: -1] (through reference chain: com.foo.Info["format"])
at com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:55)
at com.fasterxml.jackson.databind.DeserializationContext.weirdStringException(DeserializationContext.java:650)
at com.fasterxml.jackson.databind.deser.std.EnumDeserializer.deserialize(EnumDeserializer.java:85)
at com.fasterxml.jackson.databind.deser.std.EnumDeserializer.deserialize(EnumDeserializer.java:20)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:375)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:98)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:308)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:2769)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1478)
at com.fasterxml.jackson.databind.ObjectMapper.treeToValue(ObjectMapper.java:1811)
关于如何解决这个问题的任何指示?
TIA
摆脱 String name
和 List<String> other
并且只有一个字段 - List<String> names
并用 @JsonValue
序列化单个 getter
public enum ContainerFormat {
// ....
MP4("mp4", "mpeg4"),
UNKNOWN("null");
private List<String> names;
ContainerFormat(List<String> names) {
this.names = new ArrayList<String>(names);
}
@JsonValue
public List<String> getNames()
{
return this.names;
}
@JsonCreator
public static ContainerFormat getContainerFromValue(String value) throws JsonMappingException {
for (ContainerFormat format : ContainerFormat.values()) {
if(format.getValues().contains(value))
return format;
}
return UNKNOWN;
}
或者,如果您选择保留现有代码,您可以尝试使用 @JsonValue
[=27= 注释 otherValues()
]
好吧,我找到了一个解决方法:其中一个标志做了正确的事情并允许我重新读取该 mpeg4:
mapper.configure(org.codehaus.jackson.map.SerializationConfig.Feature.WRITE_NULL_PROPERTIES, false);
mapper.configure(org.codehaus.jackson.map.SerializationConfig.Feature.WRITE_ENUMS_USING_TO_STRING, true);
mapper.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.READ_ENUMS_USING_TO_STRING, true);
mapper.setPropertyNamingStrategy(org.codehaus.jackson.map.PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
mapper.setSerializationInclusion(org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion.NON_EMPTY);
mapper.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
我根据Florin的回答找到了一个很好的解决方案:
jackson 2.7.0-rc2 的正确配置(可能也是之前)
private ObjectMapper createObjectMapper() {
final ObjectMapper mapper = new ObjectMapper();
// enable toString method of enums to return the value to be mapped
mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
return mapper;
}
在您的枚举中,您只需覆盖 toString() 方法:
public enum EXAMPLE_TYPE {
START("start"),
MORE("more");
// the value which is used for matching
// the json node value with this enum
private final String value;
SectionType(final String type) {
value = type;
}
@Override
public String toString() {
return value;
}
}
您不需要任何注释或自定义反序列化程序。
我在反序列化具有多个值名称的枚举时遇到问题。下面是一个示例:Info 是一个 Java class,里面有一个具有多个名称的枚举:
public class Info {
//...
private ContainerFormat format;
}
// ContainerFormat.java:
public enum ContainerFormat {
// ....
MP4("mp4", "mpeg4"),
UNKNOWN("null");
private String name;
private List<String> others;
ContainerFormat(String name) {
this.name = name;
}
/** The service does not always return the same String for output formats.
* This 'other' string fixes the deserialization issues caused by that.
*/
ContainerFormat(String name, String... others) {
this.name = name;
this.others = new ArrayList<String>();
for (String other : others) {
this.others.add(other);
}
}
@JsonValue
@Override
public String toString() {
return name;
}
public List<String> otherNames() {
return others;
}
@JsonCreator
public static ContainerFormat fromValue(String other) throws JsonMappingException {
for (ContainerFormat format : ContainerFormat.values()) {
if (format.toString().equalsIgnoreCase(other)) {
return format;
}
if (format.otherNames() != null && format.otherNames().contains(other)) {
return format;
}
}
return UNKNOWN;
}
}
问题是当我反序列化包含 "mpeg4" 而不是 mp4 的内容时出现此错误:
com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not construct instance of com.foo.ContainerFormat from String value 'mpeg4': value not one of declared Enum instance names
at [Source: N/A; line: -1, column: -1] (through reference chain: com.foo.Info["format"])
at com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:55)
at com.fasterxml.jackson.databind.DeserializationContext.weirdStringException(DeserializationContext.java:650)
at com.fasterxml.jackson.databind.deser.std.EnumDeserializer.deserialize(EnumDeserializer.java:85)
at com.fasterxml.jackson.databind.deser.std.EnumDeserializer.deserialize(EnumDeserializer.java:20)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:375)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:98)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:308)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:2769)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1478)
at com.fasterxml.jackson.databind.ObjectMapper.treeToValue(ObjectMapper.java:1811)
关于如何解决这个问题的任何指示?
TIA
摆脱 String name
和 List<String> other
并且只有一个字段 - List<String> names
并用 @JsonValue
public enum ContainerFormat {
// ....
MP4("mp4", "mpeg4"),
UNKNOWN("null");
private List<String> names;
ContainerFormat(List<String> names) {
this.names = new ArrayList<String>(names);
}
@JsonValue
public List<String> getNames()
{
return this.names;
}
@JsonCreator
public static ContainerFormat getContainerFromValue(String value) throws JsonMappingException {
for (ContainerFormat format : ContainerFormat.values()) {
if(format.getValues().contains(value))
return format;
}
return UNKNOWN;
}
或者,如果您选择保留现有代码,您可以尝试使用 @JsonValue
[=27= 注释 otherValues()
]
好吧,我找到了一个解决方法:其中一个标志做了正确的事情并允许我重新读取该 mpeg4:
mapper.configure(org.codehaus.jackson.map.SerializationConfig.Feature.WRITE_NULL_PROPERTIES, false);
mapper.configure(org.codehaus.jackson.map.SerializationConfig.Feature.WRITE_ENUMS_USING_TO_STRING, true);
mapper.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.READ_ENUMS_USING_TO_STRING, true);
mapper.setPropertyNamingStrategy(org.codehaus.jackson.map.PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
mapper.setSerializationInclusion(org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion.NON_EMPTY);
mapper.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
我根据Florin的回答找到了一个很好的解决方案:
jackson 2.7.0-rc2 的正确配置(可能也是之前)
private ObjectMapper createObjectMapper() {
final ObjectMapper mapper = new ObjectMapper();
// enable toString method of enums to return the value to be mapped
mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
return mapper;
}
在您的枚举中,您只需覆盖 toString() 方法:
public enum EXAMPLE_TYPE {
START("start"),
MORE("more");
// the value which is used for matching
// the json node value with this enum
private final String value;
SectionType(final String type) {
value = type;
}
@Override
public String toString() {
return value;
}
}
您不需要任何注释或自定义反序列化程序。