从 JSON 反序列化 java 枚举
Posted
技术标签:
【中文标题】从 JSON 反序列化 java 枚举【英文标题】:Deserialize java enum from JSON 【发布时间】:2013-09-01 13:00:28 【问题描述】:我们使用 Jackson 1.9.1 序列化和反序列化与 Java 对象之间的 JSON 请求响应字符串。原始 Java 类型、集合类型和自定义对象被(反)序列化而没有问题。但是,我在尝试将 JSON 字符串反序列化为 java 枚举时遇到问题。 JSON字符串是这样序列化的:
"wt":"wt":100.5,"unit":"LBS":3
wt 的 Java 类型是这样的:
public class Weight
protected double weight;
protected Unit unit;
我在 SO 上提到了 this、this 和 this,并提出了重量单位的枚举,如下所示:
public enum Unit
KG("kg"),
GM("gm"),
LBS("lbs"),
OZ("oz");
private String value;
private WeightMeasurementUnit(String value) this.value = value;
@JsonValue
public String getValue() return this.value;
@JsonCreator
public static Unit create(String val)
Unit[] units = Unit.values();
for (Unit unit : units)
if (unit.getValue().equals(val))
return unit;
return LBS;
问题是,当我尝试反序列化上述 JSON 时,我收到此错误消息:“无法识别的字段“LBS”(类 a.b.c.d.Weight),未标记为可忽略”异常堆栈跟踪如下:
Caused by: org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "LBS" (Class a.b.c.d.Weight), not marked as ignorable
at [Source: java.io.ByteArrayInputStream@20172017; line: 1, column: 464] (through reference chain: a.b.c.d.MyRequest["blah"]->a.b.c.d.AnotherType["wt"]->a.b.c.d.Weight["LBS"])
at org.codehaus.jackson.map.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:53)
at org.codehaus.jackson.map.deser.StdDeserializationContext.unknownFieldException(StdDeserializationContext.java:267)
at org.codehaus.jackson.map.deser.std.StdDeserializer.reportUnknownProperty(StdDeserializer.java:673)
at org.codehaus.jackson.map.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:659)
at org.codehaus.jackson.map.deser.BeanDeserializer.handleUnknownProperty(BeanDeserializer.java:1365)
...
我的问题是: 枚举的序列化 JSON 字符串是否正确? 为了正确反序列化枚举,我还应该包含(或注释)什么?
【问题讨论】:
只是猜测 - 看起来它在序列化时按顺序编号您的枚举字段,KG = 1,GM = 2 等。如果您使用这些数字作为枚举初始化程序,它是否有效,即使用 KG(1 );总经理(2);磅(3);盎司(4);在枚举单元的定义中? 你的问题解决了我的问题。我正在寻找注释@JsonValue
和@JsonCreator
。
非常正确;在获取值的 getValue/OverriddenToString 上添加了 @JsonValue
,在匹配 EnumName/EnumValue 的 matchFromString 自定义方法上添加了 @JsonCreator
!
【参考方案1】:
我假设在 public enum Unit
代码块中,您的意思是 Unit
而不是 WeightMeasurementUnit
。
Weight
类只有一个weight
和一个unit
,所以如果你通过"wt":100.5,"unit":"lbs"
,它应该可以工作,因为unit
只是一个没有价值的单位。所以反序列化器无法将"LBS":3
解析为Unit
。 3
是干什么用的?
另一个问题是您的值是“lbs”,而您传递的是“LBS”。所以要么你需要标准化,要么你需要使用unit.getValue().equalsIgnoreCase(val)
【讨论】:
我认为问题中的字符串是它如何序列化 JSON - 所以不能直接控制来改变它 Raze2Dust:我的错。是的,我的意思是 Unit 而不是 WeightMeasurementUnit。 我几乎无法控制 JSON 的序列化方式。但是,在我可以说 JSON 序列化错误之前,我想确保我没有对枚举做任何错误。谢谢。 @Raze2Dust:这就是问题所在。以这种方式序列化 JSON 的代码使用了错误的 ObjectMapper 映射。我刚刚更改了我的 Unit 枚举以覆盖 toString 并使用 (at)JsonValue 对其进行注释【参考方案2】:我建议您将 jackson 版本更新为 2.7.0-rc2(也可能更早),然后按如下方式配置 ObjectMapper:
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 Unit
KG,
GM,
LBS,
OZ;
// UPDATE: implicitly already the default so override not needed in this case
@Override
public String toString()
return name();
您不需要任何注释或自定义反序列化程序。 这是将简单枚举映射到 json 的方法,反之亦然。
如果你的枚举应该从一个特殊的字符串映射,你必须添加一个值字段和一个构造函数,它分配这个字段并在 toString 方法中返回值。
public enum Unit
KG("kilogram"),
GM("gram"),
LBS("blah"),
OZ("anything");
Unit(final String value)
this.value = value;
@Override
public String toString()
return value;
【讨论】:
值未在最后的单元枚举类中定义以上是关于从 JSON 反序列化 java 枚举的主要内容,如果未能解决你的问题,请参考以下文章