Java >> Tutorial de Java >  >> Java

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]
    }
}

Etiqueta Java