2017-10-16 9 views
0

J'ai essayé toutes sortes de solutions pour que cela fonctionne. Mais sans succès.Parse JSON à générique profondément imbriqué avec jackson

J'ai quelques cours comme celui-ci

class Level1<T> { 

    public Level2<T> l2; 
} 

class Level2<T> { 

    public Level3<T> l3; 
} 

class Level3<T> { 

    public List<T> objectsList; 
} 

T dans ce cas peut être un objet, et devrait être possible d'être résolus lors de l'exécution.

Mon JSON ressemble à ceci:

{ 
    "Level1": { 
     "Level2": { 
      "Level3": { 
       "genericObject": [ 
        { 
         "attribute1": ..., 
         "attribute2": ... 
        }, 
        { 
         "attribute1": ..., 
         "attribute2": ... 
        } 
       ] 
      } 
     } 
    } 
} 

La propriété JSON « genericObject » change de nom et les attributs en fonction de quel type d'objet que je reçois.

J'ai essayé de définir dans mon ObjectMapper comme celui-ci, où je passe un objet de classe à ma fonction (genericObjectClass):

JavaType javaType = TypeFactory.defaultInstance().constructParametricType(ArrayList.class, List.class, genericObjectClass); 
javaType = TypeFactory.defaultInstance().constructParametricType(Level3.class, javaType); 
javaType = TypeFactory.defaultInstance().constructParametricType(Level2.class, javaType); 
javaType = TypeFactory.defaultInstance().constructParametricType(Level1.class, javaType); 

Level1<genericObject> l1 = objectMapper.readValue(jsonString, javaType); 

solutions essayées:

(de)serialising Nested Generics in Jackson

How to use Jackson with Generics

Is Jackson really unable to deserialize json into a generic type?

Répondre

0

Il y a plusieurs choses que vous devez changer

  1. objet n'est pas niveau1 l'objet racine, mais un champ. Si vous ne voulez pas créer un objet plus d'emballage, utilisez UNWRAP_ROOT_VALUE

    mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE); 
    
  2. Vous n'avez pas besoin de constructParametricType pour toute la hiérarchie d'objets, juste construire pour la classe supérieure dans la chaîne

    constructParametricType(Level1.class, genericObjectClass); 
    
  3. Vos champs json ne correspondent pas aux champs pojo. Vous devez donc annoter vos champs POJO avec @JsonProperty("Level2")@JsonProperty("genericObject") et ainsi de suite.

donc votre code désérialisation devrait ressembler à

ObjectMapper mapper = new ObjectMapper(); 
mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE); 

JavaType javaType = TypeFactory.defaultInstance() 
     .constructParametricType(Level1.class, c); 

mapper.readValue(json, javaType); 

Et les classes ressemblent

class Level1<T> { 
    @JsonProperty("Level2") 
    public Level2<T> l2; 
} 
class Level2<T> { 
    @JsonProperty("Level3") 
    public Level3<T> l3; 
} 
class Level3<T> { 
    @JsonProperty("genericObject") 
    public List<T> objectsList; 
} 

Et voici plein travail gist demo

+0

Merci pour votre réponse. Mais ce que je voulais dire par "genericObject", c'est que @JsonProperty va changer pendant l'exécution. Par conséquent, je ne pouvais pas faire quelque chose comme @JsonProperty ("genericObject"), car il pourrait y avoir plusieurs types de POJO. Je vais essayer la TypeFactory comme vous l'avez suggéré, pour voir si cela fonctionne. Je vous remercie! – alexluz

+0

@alexluz si vous avez des noms de champs différents dans votre json, c'est bien et vous n'avez probablement pas besoin d'utiliser '@ JsonProperty' pour différents POJO. Mais les noms de champs json doivent être exactement les mêmes que dans le POJO que vous voulez désérialiser. Générique ou non, ils doivent correspondre.Si vous ne pouvez pas le faire, vous devez écrire un désérialiseur personnalisé. Mais, après votre commentaire, il semble que vous pouvez simplement ignorer cette partie de ma réponse. – varren