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序列化的所有枚举,因此您将失去自己控制它的能力。。。