242 votes

Jackson - Désérialiser en utilisant une classe générique

J'ai une chaîne json, que je dois dé-sérialiser dans la classe suivante

class Data <T> {
    int found;
    Class<T> hits
}

Comment dois-je m'y prendre ? Voici la méthode habituelle

mapper.readValue(jsonString, Data.class);

Mais comment mentionner ce que T veut dire ?

402voto

Eser Aygün Points 2340

Vous devez créer un TypeReference pour chaque type générique que vous utilisez et utilisez-le pour la désérialisation. Par exemple -

mapper.readValue(jsonString, new TypeReference<Data<String>>() {});

128voto

StaxMan Points 34626

Vous ne pouvez pas faire cela : vous devez spécifier le type entièrement résolu, comme Data<MyType> . T est juste une variable, et as n'a pas de sens.

Mais si vous voulez dire que T sera connu, mais pas statiquement, vous devez créer un équivalent de TypeReference de manière dynamique. Les autres questions référencées le mentionnent peut-être déjà, mais cela devrait ressembler à quelque chose comme ça :

public Data<T> read(InputStream json, Class<T> contentClass) {
   JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, contentClass);
   return mapper.readValue(json, type);
}

40voto

CharlieQ Points 199

La première chose à faire est de sérialiser, puis de désérialiser.
donc quand vous faites la sérialisation, vous devez utiliser @JsonTypeInfo pour permettre à jackson d'écrire les informations de classe dans vos données json. Ce que vous pouvez faire est comme ceci :

Class Data <T> {
    int found;
    @JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class")
    Class<T> hits
}

Ensuite, lorsque vous désérialisez, vous constaterez que Jackson a désérialisé vos données dans une classe qui correspond à votre variable au moment de l'exécution.

31voto

davidh Points 107

Depuis Jackson 2.5, une manière élégante de résoudre ce problème est d'utiliser la fonction TypeFactory.constructParametricType(Classe paramétrée, Classe... parameterClasses) méthode qui permet de définir de façon précise un Jackson JavaType en spécifiant la classe paramétrée et ses types paramétrés.

Supposons que vous voulez désérialiser en Data<String> vous pouvez le faire :

// the json variable may be a String, an InputStream and so for...
JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, String.class);
Data<String> data = mapper.readValue(json, type);

Notez que si la classe déclarait plusieurs types paramétrés, ce ne serait pas vraiment plus difficile :

class Data <T, U> {
    int found;
    Class<T> hits;
    List<U> list;
}

Nous pourrions faire :

JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, String.class, Integer);
Data<String, Integer> data = mapper.readValue(json, type);

16voto

Devesh Points 191

Pour la classe Data<>

ObjectMapper mapper = new ObjectMapper();
JavaType type = mapper.getTypeFactory().constructParametrizedType(Data.class, Data.class, Parameter.class);
Data<Parameter> dataParam = mapper.readValue(jsonString,type)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X