Удаление десериализации перечисления с помощью Jackson
Я пытаюсь и не пытаюсь десериализовать перечисление с помощью 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: ...
Что я делаю неправильно?
Ответы
Ответ 1
EDIT: Начиная с Jackson 2.6, вы можете использовать @JsonProperty
для каждого элемента перечисления, чтобы указать его значение для сериализации/десериализации (см. здесь):
public enum Status {
@JsonProperty("ready")
READY,
@JsonProperty("notReady")
NOT_READY,
@JsonProperty("notReadyAtAll")
NOT_READY_AT_ALL;
}
(Остальная часть этого ответа по-прежнему действительна для более старых версий Jackson)
Вы должны использовать @JsonCreator
для аннотации статического метода, который получает аргумент String
. То, что Джексон называет методом factory:
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
Поскольку метод factory ожидает String
, вы должны использовать допустимый синтаксис JSON для строк, который должен иметь указанное значение.
Ответ 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
}
Ответ 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]
}
}
Ответ 5
@JsonCreator
public static Status forValue(String name)
{
return EnumUtil.getEnumByNameIgnoreCase(Status.class, name);
}
Добавление этого статического метода решит проблему десериализации