Java Jackson:将枚举值序列化和反序列化为整数
考虑以下枚举和类:Java Jackson:将枚举值序列化和反序列化为整数,java,json,serialization,enums,jackson,Java,Json,Serialization,Enums,Jackson,考虑以下枚举和类: 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 = n
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);
}
目前,该主管道的输出为:
{"name" : "Machine 1", "numCores" : 8, "state" : "OFF"}
这个输出对我来说不好,因为我希望它是0
,而不是状态的字符串“OFF”
,这是枚举状态中OFF
的顺序值
所以我想要得到的实际结果是:
{"name" : "Machine 1", "numCores" : 8, "state" : 0}
有什么优雅的方法可以让它以这种方式运行吗?如果您想打印枚举的序号,可以将构造函数更改为接受int
而不是State
,然后在调用Machine
时,您可以用以下方式构造它:
Machine m=新机器(“机器1”,8,State.OFF.ordinal())代码>
这将获取传入状态的枚举序号值,并打印以下内容
{name='Machine 1',numCores=8,state=0}
为了完成,我发布了另一种方式:自定义序列化程序:
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(){...}
}
公共类StateSerializer扩展JsonSerializer{
public void serialize(状态值、JsonGenerator生成器、SerializerProvider提供程序)引发IOException、JsonProcessingException{
generator.writeStartObject();
generator.writeFieldName(“id”);
generator.WriteEnumber(value.getId());
generator.writeEndObject();
}
}
@JsonSerialize(使用=StateSerializer.class)
公共枚举状态{
...
public int getId(){…}
}
它应该通过指定JsonValue
mapper来工作
public enum State {
OFF,
ON,
UNKNOWN;
@JsonValue
public int toValue() {
return ordinal();
}
}
这也适用于反序列化,如@JsonValue
注释的Javadoc中所述:
注意:当用于Java枚举时,另一个特性是该值
由带注释的方法返回的值也被视为
从反序列化,而不仅仅是要序列化为的JSON字符串。这是
可能,因为枚举值集是常量,并且可以
定义映射,但通常不能对POJO类型进行映射;作为
因此,这不用于POJO反序列化
您可以使用设置
objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_INDEX);
有关完整的测试用例,请参见
感谢tip at还有另一种方式:
public enum State {
@JsonProperty("0")
OFF,
@JsonProperty("1")
ON,
@JsonProperty("2")
UNKNOWN
}
但是,这将生成{“state”:“1”}
,而不是{“state”:1}
(字符串,不是数字)。在大多数情况下,您可以这样使用它
import com.fasterxml.jackson.annotation.JsonFormat;
@JsonFormat(shape = JsonFormat.Shape.NUMBER)
public enum State {
OFF,
ON,
UNKNOWN
}
我喜欢这种变通方法。我会等待其他答案,因为可能会有更优雅的方式it@TomC您的第一行代码将容易出现编译时错误,因为实际参数中的参数(最后一行)是整数,而构造函数实际上具有枚举类型。。感谢yo@VikrantKashyap我在回答中特别指出,构造函数必须从一种类型的State
更改为int
请参见:将构造函数更改为接受int
而不是State
事实上,如果您在上面的toValue()
方法上放置调试语句,您会注意到,Jackson对toValue()
的调用数量与枚举值的数量一样多。只有在处理枚举序号时,此解决方案才有效。如果枚举有一个整数字段,@JsonValue
无法工作,我们需要使用@JsonCreator
注释声明一个静态方法来解析相应的枚举。这里有一个相同的开放性bug-也可以对Enum使用Mixin,例如,接口EnumMixin{@JsonValue int ordinal();}
-不要忘记在对象映射器中注册它。我的重点是一个无注释的实现。一定要回答ON=0
,OFF=1
,在我看来并不是一件友好的事情。。。只是说;-)@Julien这花了我4年时间,但我终于采纳了你的建议并修复了它:PIt可能有效,但这也要求你在每个枚举项之前编写@JsonProperty
,并自己维护序号。实现一个只返回序号的方法,这是一种更好的做法,而且更加健壮。@SomethingSomething另一方面,在OFF和UNKNOWN之间放置一个新的枚举值(或删除现有值)将破坏基于序号的行为,因此无论如何都需要维护这是正确的。我同意你的答案值得发表。这应该是可以接受的答案,干扰越小,干扰越大,因为它会影响由ObjectMapper序列化的所有枚举,因此您将失去自己控制它的能力。。。