2015-07-29 21 views
23

Ich versuche und versäumt, eine Enum mit Jackson 2.5.4 deserialize, und ich sehe nicht ganz meinen Fall da draußen. Meine Eingabezeichenfolgen sind camel case, und ich möchte einfach den Standard-Enum-Konventionen zuordnen.Deserialisieren einer Enum mit 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; 
    } 
} 

Ich habe auch versucht @JsonValue auf einem Getter ohne Erfolg, die eine Option war ich an anderer Stelle berichtet sah. Sie alle explodieren mit:

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

Was mache ich falsch?

+0

@FedericoPeraltaSchaffner, ich wünschte, das wahr wäre, aber es ist sicherlich bläst immer noch - ich habe gerade überprüft. Ich denke, es kann nicht mit der Vielfalt der Fälle umgehen. – jwilner

+0

@FedericoPeraltaSchaffner: Same - "Wert nicht einer der deklarierten Enum Instanznamen" – jwilner

+0

Wie wäre es, wenn Sie "READY" versuchen? – Simon

Antwort

39

EDIT: von Jackson Ab 2.6 können Sie @JsonProperty auf jedem Element der Enumeration verwenden, um seine Serialisierung/Deserialisierung Wert (see here) angeben:

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

(Der Rest dieser Antwort ist immer noch gültig für ältere Versionen von Jackson)

Sie sollten @JsonCreator verwenden, um eine statische Methode zu kommentieren, die ein String Argument erhält. Das ist, was Jackson nennt Factory-Methode:

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)); 
    } 
} 

Dies ist der Test:

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 

Da die Factory-Methode ein String erwartet, Sie JSON gültige Syntax für Zeichenketten verwenden, was zu habe den angegebenen Wert.

+0

Der Eingabe-String ist "bereit", nicht "READY". – jwilner

+1

Ugh Ich habe gerade festgestellt, dass es die ganze Zeit eine Instanzmethode in meinem Beispiel war. Schlampig. Danke, dass du darauf hingewiesen hast. – jwilner

+0

Ich möchte, dass Jackson 'READY',' NOT_READY' und 'NOT_READY_AT_ALL' zusätzlich zu' ready', 'notReady' und' notReadyAtAll' deserialisiert. Wie kann ich es tun? Ich kann versuchen: try {return Status.valueOf (string); } catch (IllegalArgumentException e) {} ' am Anfang von fromString(). Gibt es eine bessere Lösung? –

7

Dies ist wahrscheinlich ein schneller Weg, es zu tun:

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 
} 
Verwandte Themen