Deserializar una enumeración con Jackson
EDITAR: A partir de Jackson 2.6, puede usar @JsonProperty
en cada elemento de la enumeración para especificar su valor de serialización/deserialización (ver aquí):
public enum Status {
@JsonProperty("ready")
READY,
@JsonProperty("notReady")
NOT_READY,
@JsonProperty("notReadyAtAll")
NOT_READY_AT_ALL;
}
(El resto de esta respuesta sigue siendo válida para versiones anteriores de Jackson)
Deberías usar @JsonCreator
para anotar un método estático que recibe un String
argumento. Eso es lo que Jackson llama un método de fábrica :
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));
}
}
Esta es la prueba:
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
Como el método de fábrica espera un String
, debe usar la sintaxis válida de JSON para las cadenas, que es tener el valor entrecomillado.
Esta es probablemente una forma más rápida de hacerlo:
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
}
Para quien esté buscando enumeraciones con propiedades json enteras. Esto es lo que funcionó para mí:
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]
}
}