Comment désérialiser une chaîne JSON qui contient des valeurs d'énumération insensibles à la casse? (en utilisant Jackson Databind)
La chaîne JSON:
[{"url": "foo", "type": "json"}]
et mon Java POJO:
public static class Endpoint {
public enum DataType {
JSON, HTML
}
public String url;
public DataType type;
public Endpoint() {
}
}
dans ce cas, la désérialisation du JSON avec "type":"json"
échouerait là où "type":"JSON"
cela fonctionnerait. Mais je veux "json"
aussi travailler pour des raisons de convention de dénomination.
La sérialisation du POJO entraîne également des majuscules "type":"JSON"
J'ai pensé à utiliser @JsonCreator
et @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();
}
Et ça a marché. Mais je me demandais s'il y avait une meilleure solutuon parce que cela me semble être un hack.
Je peux aussi écrire un désérialiseur personnalisé mais j'ai beaucoup de POJO différents qui utilisent des énumérations et ce serait difficile à maintenir.
Quelqu'un peut-il suggérer une meilleure façon de sérialiser et de désérialiser les énumérations avec une convention de dénomination appropriée?
Je ne veux pas que mes énumérations en java soient en minuscules!
Voici un code de test que j'ai utilisé:
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));
Réponses:
Dans la version 2.4.0, vous pouvez enregistrer un sérialiseur personnalisé pour tous les types Enum ( lien vers le problème github). Vous pouvez également remplacer vous-même le désérialiseur Enum standard qui sera au courant du type Enum. Voici un exemple:
Production:
la source
Jackson 2.9
C'est maintenant très simple, en utilisant
jackson-databind
2.9.0 et plusExemple complet avec tests
la source
jackson-databind
2.9.2 fonctionne spécifiquement comme prévu.spring.jackson.mapper.accept-case-insensitive-enums=true
J'ai rencontré ce même problème dans mon projet, nous avons décidé de construire nos énumérations avec une clé de chaîne et une utilisation
@JsonValue
et un constructeur statique pour la sérialisation et la désérialisation respectivement.la source
DataType.valueOf(key.toUpperCase())
- sinon, vous n'avez vraiment rien changé. Codage défensif pour éviter une NPE:return (null == key ? null : DataType.valueOf(key.toUpperCase()))
key
champ est inutile. DansgetKey
, vous pourriez justereturn name().toLowerCase()
Depuis Jackson 2.6, vous pouvez simplement faire ceci:
Pour un exemple complet, voir l'essentiel .
la source
J'ai opté pour la solution de Sam B. mais une variante plus simple.
la source
DataType.valueOf(key.toUpperCase())
est une instanciation directe où vous avez une boucle. Cela pourrait être un problème pour un très grand nombre d'énumérations. Bien sûr, vousvalueOf
pouvez lancer une IllegalArgumentException, ce que votre code évite, c'est donc un bon avantage si vous préférez la vérification des null à la vérification des exceptions.Si vous utilisez Spring Boot
2.1.x
avec Jackson,2.9
vous pouvez simplement utiliser cette propriété d'application:spring.jackson.mapper.accept-case-insensitive-enums=true
la source
Pour ceux qui essaient de désérialiser Enum en ignorant la casse dans les paramètres GET , activer ACCEPT_CASE_INSENSITIVE_ENUMS ne servira à rien. Cela n'aidera pas car cette option ne fonctionne que pour la désérialisation du corps . Essayez plutôt ceci:
puis
La réponse et les exemples de code sont d' ici
la source
Avec mes excuses à @Konstantin Zyubin, sa réponse était proche de ce dont j'avais besoin - mais je ne l'ai pas comprise, alors voici comment je pense que cela devrait se passer:
Si vous souhaitez désérialiser un type d'énumération comme insensible à la casse - c'est-à-dire que vous ne voulez pas ou ne pouvez pas modifier le comportement de l'ensemble de l'application, vous pouvez créer un désérialiseur personnalisé pour un seul type - en sous-classant
StdConverter
et en forçant Jackson de ne l'utiliser que sur les champs pertinents en utilisant l'JsonDeserialize
annotation.Exemple:
la source
Le problème est à nouveau associé à com.fasterxml.jackson.databind.util.EnumResolver . il utilise HashMap pour contenir les valeurs d'énumération et HashMap ne prend pas en charge les clés insensibles à la casse.
dans les réponses ci-dessus, tous les caractères doivent être en majuscules ou en minuscules. mais j'ai résolu tous les problèmes (in) sensibles pour les énumérations avec ça:
https://gist.github.com/bhdrk/02307ba8066d26fa1537
CustomDeserializers.java
Usage:
la source
J'ai utilisé une modification de la solution Iago Fernández et Paul.
J'avais une énumération dans mon requestobject qui devait être insensible à la casse
la source
Pour permettre la désérialisation insensible à la casse des énumérations dans jackson, ajoutez simplement la propriété ci-dessous au
application.properties
fichier de votre projet Spring Boot.Si vous disposez de la version yaml du fichier de propriétés, ajoutez la propriété ci-dessous à votre
application.yml
fichier.la source
Voici comment je gère parfois les énumérations lorsque je souhaite désérialiser de manière insensible à la casse (en s'appuyant sur le code publié dans la question):
Si l'énumération n'est pas triviale et donc dans sa propre classe, j'ajoute généralement une méthode d'analyse statique pour gérer les chaînes en minuscules.
la source
Désérialiser l'énumération avec jackson est simple. Lorsque vous souhaitez désérialiser une énumération basée sur String, vous avez besoin d'un constructeur, d'un getter et d'un setter pour votre enum.Also classe qui utilise cette enum doit avoir un setter qui reçoit DataType en tant que paramètre, pas String:
Lorsque vous avez votre json, vous pouvez désérialiser en classe Endpoint à l'aide d'ObjectMapper de Jackson:
la source