Jackson:将枚举值序列化和反序列化为整数
Posted
技术标签:
【中文标题】Jackson:将枚举值序列化和反序列化为整数【英文标题】:Jackson: Serialize and deserialize enum values as integers 【发布时间】:2016-10-16 10:59:09 【问题描述】:考虑以下枚举和类:
public enum State
OFF,
ON,
UNKNOWN
public class Machine
String name;
int numCores;
State state;
public Machine(String name, int numCores, State state)
this.name = name;
this.numCores = numCores;
this.state = state;
并考虑以下主要功能:
public static void main(String args[])
Machine m = new Machine("Machine 1", 8, State.OFF);
ObjectMapper mapper = new ObjectMapper();
String machineAsJsonString = mapper.writeValueAsString(m);
System.out.println(machineAsJsonString);
目前,这个main的输出是:
"name" : "Machine 1", "numCores" : 8, "state" : "OFF"
这个输出对我不利,因为我希望它不是state
的字符串"OFF"
,而是0
,这是枚举OFF
中OFF
的序数值State
。
所以我想要得到的实际结果是:
"name" : "Machine 1", "numCores" : 8, "state" : 0
有没有什么优雅的方法让它表现得这样?
【问题讨论】:
我对无注释实现的抨击。做回复。 pastebin.com/raw/Mvf9Ygq1ON = 0
,OFF = 1
,恕我直言,这看起来不像是友好的事情......只是说;-)
@Julien 我花了 4 年时间,但我终于采纳了你的建议并修复了它:P
【参考方案1】:
如果您想打印枚举的序数,您可以将构造函数更改为接受 int
而不是 State
,然后在调用 Machine
时,您可以按以下方式构造它:
Machine m = new Machine("Machine 1", 8, State.OFF.ordinal());
这将获取传入状态的枚举序数值并打印以下内容
name='Machine 1', numCores=8, state=0
【讨论】:
我喜欢这种解决方法。我会等待其他答案,因为可能有更优雅的方法来做到这一点 @TomC 您的第一行代码将容易出现编译时错误,因为参数(最后一个)在实际参数中是整数,而构造函数实际上具有枚举类型.. 谢谢你 @VikrantKashyap 我在回答中特别指出,必须将构造函数从State
类型更改为 int
请参阅:更改构造函数以接受 int
而不是State
【参考方案2】:
为了完成,我发布了另一种方式:自定义序列化程序:
public class StateSerializer extends JsonSerializer<State>
public void serialize(State value, JsonGenerator generator, SerializerProvider provider) throws IOException, JsonProcessingException
generator.writeStartObject();
generator.writeFieldName("id");
generator.writeNumber(value.getId());
generator.writeEndObject();
@JsonSerialize(using = StateSerializer.class)
public enum State
...
public int getId()...
【讨论】:
【参考方案3】:它应该通过指定JsonValue
mapper 来工作。
public enum State
OFF,
ON,
UNKNOWN;
@JsonValue
public int toValue()
return ordinal();
这也适用于反序列化,如 @JsonValue
注释的 Javadoc 中所述:
注意:当用于 Java 枚举时,另一个特性是该值 由带注释的方法返回的值也被认为是 反序列化,而不仅仅是要序列化为的 JSON 字符串。这是 可能,因为枚举值的集合是恒定的,并且可以 定义映射,但一般不能对 POJO 类型进行;作为 因此,这不用于 POJO 反序列化
【讨论】:
事实上,如果您在上面的toValue()
方法上添加调试语句,您会注意到Jackson 对toValue()
的调用次数与ENUM 值一样多。
这个解决方案只有在我们处理枚举序数时才有效。如果枚举有一个整数字段,@JsonValue
无法工作,我们需要声明一个带有@JsonCreator
注释的静态方法来解析适当的枚举。这是一个相同的开放错误 - github.com/FasterXML/jackson-databind/issues/1850
也可以将 Mixin 用于 Enum,例如interface EnumMixin @JsonValue int ordinal();
- 不要忘记在对象映射器中注册它。【参考方案4】:
你可以使用设置
objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_INDEX);
完整的测试用例见https://github.com/FasterXML/jackson-databind/blob/master/src/test/java/com/fasterxml/jackson/databind/ser/TestEnumSerialization.java
感谢https://righele.it/2016/01/30/jackson-deserialization-from-json-to-java-enums/的提示
【讨论】:
优秀。这应该是公认的答案,侵入性较小 它更具侵入性,因为它会影响由该 ObjectMapper 序列化的所有枚举,因此您失去了自己控制它的能力...【参考方案5】:另一种方式:
public enum State
@JsonProperty("0")
OFF,
@JsonProperty("1")
ON,
@JsonProperty("2")
UNKNOWN
但是,这将产生 "state" : "1"
而不是 "state" : 1
(字符串,而不是数字)。大多数情况下都可以的
【讨论】:
它可能会起作用,但这也需要你在每个枚举项之前写@JsonProperty
,并自己维护序数。实现一个只返回序数的方法,变成了一种更好的做法,也更健壮。
另一方面,@SomethingSomething 在 OFF 和 UNKNOWN 之间放置一个新的枚举值(或删除现有的枚举值)将破坏序数-based 行为,因此无论如何都需要维护
没错。同意您的答案值得发布【参考方案6】:
你可以这样使用
import com.fasterxml.jackson.annotation.JsonFormat;
@JsonFormat(shape = JsonFormat.Shape.NUMBER)
public enum State
OFF,
ON,
UNKNOWN
【讨论】:
以上是关于Jackson:将枚举值序列化和反序列化为整数的主要内容,如果未能解决你的问题,请参考以下文章