web-dev-qa-db-fra.com

Deserialize JSON to ArrayList <POJO> en utilisant Jackson

J'ai une classe Java MyPojo qui m'intéresse la désérialisation à partir de JSON. J'ai configuré une classe spéciale MixIn, MyPojoDeMixIn, pour m'aider à la désérialisation. MyPojo a seulement les variables d'instance int et String combinées avec des getters et des setters appropriés. MyPojoDeMixIn ressemble à ceci:

public abstract class MyPojoDeMixIn {
  MyPojoDeMixIn(
      @JsonProperty("JsonName1") int prop1,
      @JsonProperty("JsonName2") int prop2,
      @JsonProperty("JsonName3") String prop3) {}
}

Dans mon client de test, j'effectue les opérations suivantes, mais bien sûr, cela ne fonctionne pas à la compilation car il existe une variable JsonMappingException liée à une non-concordance de types.

ObjectMapper m = new ObjectMapper();
m.getDeserializationConfig().addMixInAnnotations(MyPojo.class,MyPojoDeMixIn.class);
try { ArrayList<MyPojo> arrayOfPojo = m.readValue(response, MyPojo.class); }
catch (Exception e) { System.out.println(e) }

Je suis conscient que je pourrais résoudre ce problème en créant un objet "Response" qui ne contient qu'un ArrayList<MyPojo>, mais je devrais alors créer ces objets quelque peu inutiles pour chaque type que je veux renvoyer.

J'ai aussi regardé en ligne sur JacksonInFiveMinutes mais j'ai passé un temps terrible à comprendre le contenu de Map<A,B> et son lien avec mon problème. Si vous ne pouvez pas le dire, je suis un novice en Java et je viens d’un milieu Obj-C. Ils mentionnent spécifiquement: 

Outre la liaison aux POJO et aux types "simples", il en existe un variante supplémentaire: celle de la liaison à des conteneurs génériques (typés) . Ce cas nécessite un traitement spécial en raison de ce que l'on appelle le type effacement (utilisé par Java pour implémenter les génériques d’une manière quelque peu rétrocompatible ), ce qui vous empêche d’utiliser quelque chose comme Collection.class (qui ne compile pas).

Donc, si vous souhaitez lier des données dans une carte, vous devez utiliser:

Map<String,User> result = mapper.readValue(src, new TypeReference<Map<String,User>>() { });

Comment puis-je désérialiser directement à ArrayList?

67
tacos_tacos_tacos

Vous pouvez désérialiser directement une liste en utilisant le wrapper TypeReference. Un exemple de méthode:

public static <T> T fromJSON(final TypeReference<T> type,
      final String jsonPacket) {
   T data = null;

   try {
      data = new ObjectMapper().readValue(jsonPacket, type);
   } catch (Exception e) {
      // Handle the problem
   }
   return data;
}

Et est utilisé ainsi:

final String json = "";
Set<POJO> properties = fromJSON(new TypeReference<Set<POJO>>() {}, json);

.

TypeReference Javadoc

118
Perception

Une autre méthode consiste à utiliser un tableau comme type, par exemple:

ObjectMapper objectMapper = new ObjectMapper();
MyPojo[] pojos = objectMapper.readValue(json, MyPojo[].class);

De cette façon, vous évitez tous les problèmes liés à l'objet Type et si vous avez vraiment besoin d'une liste, vous pouvez toujours convertir le tableau en liste en:

List<MyPojo> pojoList = Arrays.asList(pojos);

IMHO c'est beaucoup plus lisible.

Et pour en faire une liste réelle (pouvant être modifiée, voir les limitations de Arrays.asList()), procédez comme suit:

List<MyPojo> mcList = new ArrayList<>(Arrays.asList(pojos));
74
DevNG

Cette variante est plus simple et élégante.

CollectionType typeReference =
    TypeFactory.defaultInstance().constructCollectionType(List.class, Dto.class);
List<Dto> resultDto = objectMapper.readValue(content, typeReference);

J'ai aussi le même problème. J'ai un JSON qui doit être converti en ArrayList. 

Le compte ressemble à ceci.

Account{
  Person p ;
  Related r ;

}

Person{
    String Name ;
    Address a ;
}

Toutes les classes ci-dessus ont été annotées correctement . J'ai essayé TypeReference> () {} Mais ne fonctionne pas.

Cela me donne un Arraylist mais ArrayList a un linkedHashMap qui contient quelques hashmaps plus liés contenant des valeurs finales.

Mon code est comme suit:

public T unmarshal(String responseXML,String c)
{
    ObjectMapper mapper = new ObjectMapper();

    AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();

    mapper.getDeserializationConfig().withAnnotationIntrospector(introspector);

    mapper.getSerializationConfig().withAnnotationIntrospector(introspector);
    try
    {
      this.targetclass = (T) mapper.readValue(responseXML,  new TypeReference<ArrayList<T>>() {});
    }
    catch (JsonParseException e)
    {
      e.printStackTrace();
    }
    catch (JsonMappingException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }

    return this.targetclass;
}

J'ai finalement résolu le problème. Je suis en mesure de convertir la liste dans Json String directement à ArrayList comme suit:

JsonMarshallerUnmarshaller<T>{

     T targetClass ;

     public ArrayList<T> unmarshal(String jsonString)
     {
        ObjectMapper mapper = new ObjectMapper();

        AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();

        mapper.getDeserializationConfig().withAnnotationIntrospector(introspector);

        mapper.getSerializationConfig().withAnnotationIntrospector(introspector);
        JavaType type = mapper.getTypeFactory().
                    constructCollectionType(ArrayList.class, targetclass.getClass()) ;
        try
        {
        Class c1 = this.targetclass.getClass() ;
        Class c2 = this.targetclass1.getClass() ;
            ArrayList<T> temp = (ArrayList<T>) mapper.readValue(jsonString,  type);
        return temp ;
        }
       catch (JsonParseException e)
       {
        e.printStackTrace();
       }
       catch (JsonMappingException e) {
           e.printStackTrace();
       } catch (IOException e) {
          e.printStackTrace();
       }

     return null ;
    }  

}
3
rushidesai1

Cela fonctionne pour moi.

@Test
public void cloneTest() {
    List<Part> parts = new ArrayList<Part>();
    Part part1 = new Part(1);
    parts.add(part1);
    Part part2 = new Part(2);
    parts.add(part2);
    try {
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(parts);

        List<Part> cloneParts = objectMapper.readValue(jsonStr, new TypeReference<ArrayList<Part>>() {});
    } catch (Exception e) {
        //fail("failed.");
        e.printStackTrace();
    }

    //TODO: Assert: compare both list values.
}
0
Jugal Panchal