2015-07-29 5 views
23

Я пытаюсь и не пытаюсь десериализировать перечисление с помощью Jackson 2.5.4, и я не совсем вижу свое дело. Мои строки ввода - это случай верблюда, и я хочу просто сопоставить стандартные соглашения Enum.Deserializing enum with Jackson

@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: ... 

Что я делаю неправильно?

+0

@FedericoPeraltaSchaffner, я хочу, чтобы это было правдой, но это, конечно, все еще дует вверх - я только что проверил. Я думаю, что он не может справиться с множеством случаев. – jwilner

+0

@FedericoPeraltaSchaffner: То же самое - «значение не одно из объявленных имен экземпляра Enum» – jwilner

+0

Как насчет того, если вы попытаетесь «ГОТОВ»? – Simon

ответ

39

EDIT: Начиная с Джексоном 2.6, вы можете использовать @JsonProperty на каждом элементе перечисления указать его сериализации/десериализации значение (see here):

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

(Остальная часть этого ответа остается в силе для более старых версий Jackson)

Вы должны использовать @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 правильный синтаксис для строк, который должен имеют значение, указанное.

+0

Входная строка «готова», а не «ГОТОВ». – jwilner

+1

Ugh Я просто понял, что это метод экземпляра в моем примере все это время. Слоппи. Спасибо за указание на это. – jwilner

+0

Я хочу, чтобы Джексон десериализовал 'READY',' NOT_READY' и 'NOT_READY_AT_ALL' добавочно к' ready', 'notReady' и' notReadyAtAll'. Как мне это сделать? Я могу вставить 'try {return Status.valueOf (string); } catch (IllegalArgumentException e) {} ' в начале fromString(). Есть ли лучшее решение? –

7

Это, вероятно, более быстрый способ сделать это:

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 
} 
Смежные вопросы