2015-07-29 21 views
23

Sto provando e fallendo nel deserializzare un enum con Jackson 2.5.4, e non vedo proprio il mio caso là fuori. Le mie stringhe di input sono case cammello e voglio semplicemente mappare a convenzioni Enum standard.Deserializzare un enum con 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; 
    } 
} 

Ho anche provato @JsonValue su un getter senza alcun risultato, che era un'opzione ho visto riportato altrove. Scoppiano tutti con:

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

Cosa sto facendo male?

+0

@FedericoPeraltaSchaffner, vorrei che questo fosse vero, ma certamente soffia ancora in piedi - Ho appena controllato. Penso che non possa affrontare la varietà dei casi. – jwilner

+0

@FedericoPeraltaSchaffner: Same - "valore non uno dei nomi di istanza Enum dichiarati" – jwilner

+0

Che ne dici se si prova "PRONTA"? – Simon

risposta

39

EDIT: A partire da Jackson 2.6, è possibile utilizzare @JsonProperty su ogni elemento della enum per specificare il valore di serializzazione/deserializzazione (see here):

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

(Il resto di questa risposta è ancora valido per le versioni precedenti di Jackson)

È necessario utilizzare @JsonCreator per annotare un metodo statico che riceve un argomento String. Questo è quello che Jackson chiama un metodo fabbrica:

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

Questa è la prova:

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 

Come il metodo factory si aspetta una String, è necessario utilizzare JSON sintassi valida per le stringhe, che è quello di avere il valore quotato

+0

La stringa di input è "pronta", non "PRONTA". – jwilner

+1

Ugh Ho appena realizzato che era un metodo di istanza nel mio esempio per tutto il tempo. Sloppy. Grazie per averlo indicato. – jwilner

+0

Desidero che Jackson deserializzi 'READY',' NOT_READY' e 'NOT_READY_AT_ALL' addizionalmente su' ready', 'notReady' e' notReadyAtAll'. Come posso farlo? Posso inserire 'try {return Status.valueOf (string); } catch (IllegalArgumentException e) {} ' all'inizio di fromString(). C'è una soluzione migliore? –

7

Questo è probabilmente un modo più veloce per farlo:

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 
} 
Problemi correlati