杰克逊:将枚举值序列化和反序列化为整数

Som*_*ing 22 java enums serialization json jackson

考虑以下枚举和类:

public enum State {
    ON,
    OFF,
    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;
    }
}
Run Code Online (Sandbox Code Playgroud)

并考虑以下主要功能:

public static void main(String args[]) {
    Machine m = new Machine("Machine 1", 8, OFF);
    ObjectMapper mapper = new ObjectMapper();
    String machineAsJsonString = mapper.writeValueAsString(m);
    System.out.println(machineAsJsonString);
}
Run Code Online (Sandbox Code Playgroud)

目前,这个主要的输出是:

{"name" : "Machine 1", "numCores" : 8, "state" : "OFF"}
Run Code Online (Sandbox Code Playgroud)

这种输出并不适合我,因为除了字符串"OFF"state,我想它是1,这是序号值OFF在枚举State.

所以我想得到的实际结果是:

{"name" : "Machine 1", "numCores" : 8, "state" : 1}
Run Code Online (Sandbox Code Playgroud)

是否有一些优雅的方式让它表现得这样?

use*_*594 44

它应该通过指定JsonValuemapper 来工作.

public enum State {
    ON,
    OFF,
    UNKNOWN;

    @JsonValue
    public int toValue() {
        return ordinal();
    }
}  
Run Code Online (Sandbox Code Playgroud)

这也适用于反序列化,如注释的Javadoc中所述@JsonValue:

注意:当用于Java枚举时,另外一个特性是注释方法返回的值也被认为是反序列化的值,而不仅仅是要序列化的JSON字符串.这是可能的,因为Enum值的集合是常量并且可以定义映射,但是对于POJO类型通常不能完成; 因此,这不用于POJO反序列化

  • 实际上,如果你在上面的'toValue()`方法中放置一个调试语句,你会发现Jackson对`toValue()`的调用次数与许多ENUM值一样多. (2认同)
  • 这个解决方案只有在我们处理枚举时才有效.如果枚举有一个整数字段,`@ JsonValue`就无法工作,我们需要声明一个带有`@ JsonCreator`注释的静态方法来解析相应的枚举.这是一个开放的bug - https://github.com/FasterXML/jackson-databind/issues/1850 (2认同)

Mar*_*tin 13

你可以使用设置

objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_INDEX);
Run Code Online (Sandbox Code Playgroud)

有关完整的测试用例,请参阅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 序列化的所有枚举,因此您失去了自己控制它的能力...... (4认同)

das*_*nse 8

你可以这样使用

import com.fasterxml.jackson.annotation.JsonFormat;

@JsonFormat(shape = JsonFormat.Shape.NUMBER)
public enum State {
       OFF,
       ON,
       UNKNOWN
}
Run Code Online (Sandbox Code Playgroud)


Nik*_*nko 6

还有另一种方式:

public enum State {

    @JsonProperty("0")
    OFF,

    @JsonProperty("1")
    ON,

    @JsonProperty("2")
    UNKNOWN
}
Run Code Online (Sandbox Code Playgroud)

但是,这将生成{"state" : "1"}而不是{"state" : 1}(字符串,而不是数字)。大多数情况下都可以

  • 另一方面,@SomethingSomething 在 *OFF* 和 *UNKNOWN* 之间放置一个新的枚举值(或删除现有的枚举值)将破坏基于序数的行为,因此无论如何都需要维护 (2认同)

Pac*_*ato 5

为了完成我发布另一种方式:自定义序列化器:

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(){...}
}
Run Code Online (Sandbox Code Playgroud)