【问题标题】:Deserializing an enum with Jackson使用 Jackson 反序列化枚举
【发布时间】:2015-10-19 18:20:54
【问题描述】:

我正在尝试使用 Jackson 2.5.4 反序列化枚举,但未能成功,我不太了解我的情况。我的输入字符串是驼峰式大小写,我想简单地映射到标准 Enum 约定。

@JsonFormat(shape = JsonFormat.Shape.STRING)
public enum Status {
    READY("ready"),
    NOT_READY("notReady"),
    NOT_READY_AT_ALL("notReadyAtAll");

    private static Map<String, Status> FORMAT_MAP = Stream
            .of(Status.values())
            .collect(toMap(s -> s.formatted, Function.<Status>identity()));

    private final String formatted;

    Status(String formatted) {
        this.formatted = formatted;
    }

    @JsonCreator
    public Status fromString(String string) {
        Status status = FORMAT_MAP.get(string);
        if (status == null) {
            throw new IllegalArgumentException(string + " has no corresponding value");
        }
        return status;
    }
}

我还在吸气剂上尝试了@JsonValue,但无济于事,这是我在其他地方看到的一个选项。他们都爆发了:

com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not construct instance of ...Status from String value 'ready': value not one of declared Enum instance names: ...

我做错了什么?

【问题讨论】:

  • @FedericoPeraltaSchaffner,我希望这是真的,但它肯定还是会爆炸——我刚刚检查过。我认为它无法处理各种情况。
  • @FedericoPeraltaSchaffner: 相同——“值不是声明的枚举实例名称之一”
  • 试试“READY”怎么样?
  • @Simon,如果你所有的 JSON 值都完全匹配,那么它肯定可以工作——但我正在反序列化并且没有更改输入的奢侈!

标签: java json jackson


【解决方案1】:

编辑:从 Jackson 2.6 开始,您可以在枚举的每个元素上使用 @JsonProperty 来指定其序列化/反序列化值 (see here):

public enum Status {
    @JsonProperty("ready")
    READY,
    @JsonProperty("notReady")
    NOT_READY,
    @JsonProperty("notReadyAtAll")
    NOT_READY_AT_ALL;
}

(此答案的其余部分仍然适用于杰克逊的旧版本)

您应该使用@JsonCreator 来注释接收String 参数的静态方法。这就是杰克逊所说的工厂方法

public enum Status {
    READY("ready"),
    NOT_READY("notReady"),
    NOT_READY_AT_ALL("notReadyAtAll");

    private static Map<String, Status> FORMAT_MAP = Stream
        .of(Status.values())
        .collect(Collectors.toMap(s -> s.formatted, Function.identity()));

    private final String formatted;

    Status(String formatted) {
        this.formatted = formatted;
    }

    @JsonCreator // This is the factory method and must be static
    public static Status fromString(String string) {
        return Optional
            .ofNullable(FORMAT_MAP.get(string))
            .orElseThrow(() -> new IllegalArgumentException(string));
    }
}

这是测试:

ObjectMapper mapper = new ObjectMapper();

Status s1 = mapper.readValue("\"ready\"", Status.class);
Status s2 = mapper.readValue("\"notReadyAtAll\"", Status.class);

System.out.println(s1); // READY
System.out.println(s2); // NOT_READY_AT_ALL

由于工厂方法需要 String,因此您必须对字符串使用 JSON 有效语法,即引用值。

【讨论】:

  • 呃,我刚刚意识到这一直是我的示例中的一个实例方法。邋遢。感谢您指出这一点。
  • @JohannesFlügel 我只是修改工厂方法:如果字符串参数不在地图中,我会尝试使用Status.valueOf。一行:return Optional.ofNullable(FORMAT_MAP.get(string)).orElseGet(() -&gt; Status.valueOf(string));
  • 谢谢谢谢谢谢!实际上,我有一个使用更新的 jackson 构建并使用 @JsonProperty 的库。但是我的一些依赖项正在拉动较旧的杰克逊(2.5.x)。所以代码编译得很好,但 @JsonProperty 值没有得到尊重,而是使用了枚举常量名称(“AAA”而不是 @JsonProperty 中指定的“aaa”)。
  • 仅当您只有一个字段并且 JsonFormat 形状不是对象时才有效。这是针对多个字段和 @JsonFormat(shape = JsonFormat.Shape.OBJECT) @JsonCreator static PinOperationMode findValue(@JsonProperty("mode") String mode, @JsonProperty("code") String code) { return Arrays.stream(PinOperationMode .values()).filter(pt -> pt.mode.equals(mode) && pt.code.equals(code)).findFirst().get(); }
  • @FedericoPeraltaSchaffner 没问题,我在下面发布了这个案例的答案。干杯
【解决方案2】:

这可能是一种更快的方法:

public enum Status {
 READY("ready"),
 NOT_READY("notReady"),
 NOT_READY_AT_ALL("notReadyAtAll");

 private final String formatted;

 Status(String formatted) {
   this.formatted = formatted;
 }

 @Override
 public String toString() {
   return formatted;
 }
}

public static void main(String[] args) throws IOException {
  ObjectMapper mapper = new ObjectMapper();
  ObjectReader reader = mapper.reader(Status.class);
  Status status = reader.with(DeserializationFeature.READ_ENUMS_USING_TO_STRING).readValue("\"notReady\"");
  System.out.println(status.name());  // NOT_READY
}

【讨论】:

  • 这至少不适用于 >=2.8 的版本,已接受的答案似乎要好得多并且可以正常工作
  • 在从 1.5.X 到 2.4.X 的春季更新后,这对我有用。谢谢
【解决方案3】:

此页面上的解决方案仅适用于单个字段和@JsonFormat(shape = JsonFormat.Shape.NATURAL)(默认格式)

这适用于多个字段和@JsonFormat(shape = JsonFormat.Shape.OBJECT)

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum PinOperationMode {
    INPUT("Input", "I"),
    OUTPUT("Output", "O")
    ;

    private final String mode;
    private final String code;

    PinOperationMode(String mode, String code) {
        this.mode = mode;
        this.code = code;
    }

    public String getMode() {
        return mode;
    }

    public String getCode() {
        return code;
    }

    @JsonCreator
    static PinOperationMode findValue(@JsonProperty("mode") String mode, @JsonProperty("code") String code) {
        return Arrays.stream(PinOperationMode.values()).filter(pt -> pt.mode.equals(mode) && pt.code.equals(code)).findFirst().get();
    }
}

【讨论】:

    【解决方案4】:

    对于正在搜索具有整数 json 属性的枚举的人。这对我有用:

    enum class Status (private val code: Int) {
        PAST(0),
        LIVE(2),
        UPCOMING(1);
        companion object {
            private val codes = Status.values().associateBy(Status::code)
            @JvmStatic @JsonCreator fun from (value: Int) = codes[value]
        }
    }
    

    【讨论】:

    • 这对我很有帮助!我有 @JsonCreator 注释并认为这就足够了,但显然 @JvmStatic 也是必需的。
    【解决方案5】:
    @JsonCreator
    public static Status forValue(String name)
    {
        return EnumUtil.getEnumByNameIgnoreCase(Status.class, name);
    }
    

    添加此静态方法将解决您的反序列化问题

    【讨论】:

    • 虽然此代码可能会回答问题,但提供有关 why 和/或 如何 此代码回答问题的附加上下文可提高其长期价值.
    【解决方案6】:

    您可以使用@JsonCreator 注释来解决您的问题。看看https://www.baeldung.com/jackson-serialize-enums,关于 enum 和 serialize-deserialize 与 jackson lib 有足够清晰的解释。

    【讨论】:

      【解决方案7】:

      @JsonCreator(mode = JsonCreator.Mode.DELEGATING) 是我的解决方案。

      https://github.com/FasterXML/jackson-module-kotlin/issues/336#issuecomment-630587525

      【讨论】:

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