¿Cómo puedo deserializar una cadena JSON que contiene valores de enumeración que no distinguen entre mayúsculas y minúsculas? (usando Jackson Databind)
La cadena JSON:
[{"url": "foo", "type": "json"}]
y mi POJO de Java:
public static class Endpoint {
public enum DataType {
JSON, HTML
}
public String url;
public DataType type;
public Endpoint() {
}
}
en este caso, la deserialización del JSON con "type":"json"
fallaría donde "type":"JSON"
funcionaría. Pero quiero "json"
trabajar también por razones de convenciones de nombres.
Serializar el POJO también resulta en mayúsculas "type":"JSON"
Pensé en usar @JsonCreator
y @JsonGetter:
@JsonCreator
private Endpoint(@JsonProperty("name") String url, @JsonProperty("type") String type) {
this.url = url;
this.type = DataType.valueOf(type.toUpperCase());
}
//....
@JsonGetter
private String getType() {
return type.name().toLowerCase();
}
Y funcionó. Pero me preguntaba si hay una mejor solución porque esto me parece un truco.
También puedo escribir un deserializador personalizado, pero tengo muchos POJO diferentes que usan enumeraciones y sería difícil de mantener.
¿Alguien puede sugerir una mejor manera de serializar y deserializar enumeraciones con la convención de nomenclatura adecuada?
¡No quiero que mis enumeraciones en Java estén en minúsculas!
Aquí hay un código de prueba que utilicé:
String data = "[{\"url\":\"foo\", \"type\":\"json\"}]";
Endpoint[] arr = new ObjectMapper().readValue(data, Endpoint[].class);
System.out.println("POJO[]->" + Arrays.toString(arr));
System.out.println("JSON ->" + new ObjectMapper().writeValueAsString(arr));
Respuestas:
En la versión 2.4.0 puede registrar un serializador personalizado para todos los tipos de Enum ( enlace al problema de github). También puede reemplazar el deserializador estándar de Enum por su cuenta que estará al tanto del tipo de Enum. Aquí hay un ejemplo:
Salida:
fuente
Jackson 2.9
Esto ahora es muy simple, usando
jackson-databind
2.9.0 y superiorEjemplo completo con pruebas
fuente
jackson-databind
2.9.2 funciona específicamente como se esperaba.spring.jackson.mapper.accept-case-insensitive-enums=true
Me encontré con este mismo problema en mi proyecto, decidimos construir nuestras enumeraciones con una clave de cadena y uso
@JsonValue
y un constructor estático para serialización y deserialización respectivamente.fuente
DataType.valueOf(key.toUpperCase())
; de lo contrario, realmente no ha cambiado nada. Codificación defensiva para evitar una NPE:return (null == key ? null : DataType.valueOf(key.toUpperCase()))
key
campo es innecesario. EngetKey
, podría simplementereturn name().toLowerCase()
Desde Jackson 2.6, simplemente puede hacer esto:
Para obtener un ejemplo completo, consulte esta esencia .
fuente
Fui por la solución de Sam B. pero una variante más simple.
fuente
DataType.valueOf(key.toUpperCase())
es una instanciación directa en la que tienes un bucle. Esto podría ser un problema para una enumeración muy numerosa. Por supuesto,valueOf
puede lanzar una IllegalArgumentException, que su código evita, por lo que es un buen beneficio si prefiere la verificación nula a la verificación de excepciones.Si está usando Spring Boot
2.1.x
con Jackson2.9
, simplemente puede usar esta propiedad de la aplicación:spring.jackson.mapper.accept-case-insensitive-enums=true
fuente
Para aquellos que intentan deserializar Enum ignorando el caso en los parámetros GET , habilitar ACCEPT_CASE_INSENSITIVE_ENUMS no servirá de nada. No ayudará porque esta opción solo funciona para la deserialización del cuerpo . En su lugar, intente esto:
y entonces
Las muestras de código y respuesta son de aquí
fuente
Con disculpas para @Konstantin Zyubin, su respuesta estuvo cerca de lo que necesitaba, pero no lo entendí, así que así es como creo que debería ser:
Si desea deserializar un tipo de enumeración sin distinción entre mayúsculas y minúsculas, es decir, no desea, o no puede, modificar el comportamiento de toda la aplicación, puede crear un deserializador personalizado solo para un tipo, subclasificando
StdConverter
y forzando Jackson para usarlo solo en los campos relevantes que usan laJsonDeserialize
anotación.Ejemplo:
fuente
El problema se relaciona con com.fasterxml.jackson.databind.util.EnumResolver . usa HashMap para contener valores de enumeración y HashMap no admite claves que no distinguen entre mayúsculas y minúsculas.
en las respuestas anteriores, todos los caracteres deben estar en mayúsculas o minúsculas. pero arreglé todos los problemas (in) sensibles para enumeraciones con eso:
https://gist.github.com/bhdrk/02307ba8066d26fa1537
CustomDeserializers.java
Uso:
fuente
Usé una modificación de la solución de Iago Fernández y Paul.
Tenía una enumeración en mi objeto de solicitud que debía distinguir entre mayúsculas y minúsculas
fuente
Para permitir la deserialización de enumeraciones que no distingue entre mayúsculas y minúsculas en jackson, simplemente agregue la siguiente propiedad al
application.properties
archivo de su proyecto de arranque de primavera.Si tiene la versión yaml del archivo de propiedades, agregue la siguiente propiedad a su
application.yml
archivo.fuente
Así es como a veces manejo las enumeraciones cuando quiero deserializar de manera que no distingue entre mayúsculas y minúsculas (basándose en el código publicado en la pregunta):
Si la enumeración no es trivial y, por lo tanto, en su propia clase, generalmente agrego un método de análisis estático para manejar cadenas en minúsculas.
fuente
Deserializar enum con jackson es simple. Cuando desee deserializar una enumeración basada en String, necesita un constructor, un getter y un setter para su enum.También la clase que usa esa enumeración debe tener un setter que reciba DataType como param, no String:
Cuando tenga su json, puede deserializar a la clase Endpoint usando ObjectMapper of Jackson:
fuente