【问题标题】:Jackson: Serialize and deserialize enum values as integersJackson:将枚举值序列化和反序列化为整数
【发布时间】: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,这是枚举OFFOFF 的序数值State

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

{"name" : "Machine 1", "numCores" : 8, "state" : 0}

有没有什么优雅的方法让它表现得这样?

【问题讨论】:

  • 我对无注释实现的抨击。做回复。 pastebin.com/raw/Mvf9Ygq1
  • ON = 0OFF = 1,恕我直言,这看起来不像是友好的事情......只是说;-)
  • @Julien 我花了 4 年时间,但我终于采纳了你的建议并修复了它:P

标签: java json serialization enums jackson


【解决方案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 序列化的所有枚举,因此您失去了自己控制它的能力...
    【解决方案5】:

    另一种方式:

    public enum State {
    
        @JsonProperty("0")
        OFF,
    
        @JsonProperty("1")
        ON,
    
        @JsonProperty("2")
        UNKNOWN
    }
    

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

    【讨论】:

    • 它可能会起作用,但这也需要你在每个枚举项之前写@JsonProperty,并自己维护序数。实现一个只返回序数的方法,变成了一种更好的做法,也更健壮。
    • 另一方面,@SomethingSomething 在 OFFUNKNOWN 之间放置一个新的枚举值(或删除现有的枚举值)将破坏序数-based 行为,因此无论如何都需要维护
    • 没错。同意您的答案值得发布
    【解决方案6】:

    你可以这样使用

    import com.fasterxml.jackson.annotation.JsonFormat;
    
    @JsonFormat(shape = JsonFormat.Shape.NUMBER)
    public enum State {
           OFF,
           ON,
           UNKNOWN
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-31
      • 1970-01-01
      • 2021-12-27
      • 2015-10-19
      • 2020-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多