JSON'u Jackson kullanarak ArrayList <POJO> için seriyi kaldır


100

MyPojoJSON'dan seri durumdan çıkarmak istediğim bir Java sınıfım var. Seriyi kaldırma işleminde MyPojoDeMixInbana yardımcı olması için özel bir MixIn sınıfı yapılandırdım . uygun alıcılar ve ayarlayıcılarla birleştirilmiş MyPojoyalnızca intve Stringörnek değişkenlerine sahiptir . MyPojoDeMixInşuna benzer:

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

Test istemcimde aşağıdakileri yapıyorum, ancak elbette derleme zamanında çalışmıyor çünkü JsonMappingExceptionbir tür uyuşmazlığı ile ilgili bir durum var.

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) }

ArrayList<MyPojo>İçinde yalnızca bir "Response" nesnesi olan bir "Response" nesnesi oluşturarak bu sorunu hafifletebileceğimin farkındayım , ancak o zaman geri dönmek istediğim her tür için bu biraz işe yaramaz nesneleri yaratmak zorunda kalacağım.

Ayrıca çevrimiçi olarak JacksonInFiveMinutes'e baktım, ancak konuyla ilgili konuları ve sorunumlaMap<A,B> nasıl ilişkili olduğunu anlamakta çok zorlandım . Söyleyemezseniz, Java'da tamamen yeniyim ve Obj-C geçmişinden geliyorum. Özellikle belirtiyorlar:

POJO'lara ve "basit" türlere bağlanmaya ek olarak, ek bir değişken daha vardır: genel (tiplenmiş) kapsayıcılara bağlanma. Bu durum, Collection.class (derlenmeyen) gibi bir şeyi kullanmanızı engelleyen sözde Tür Silme (jenerikleri biraz geriye dönük olarak uygulamak için Java tarafından kullanılır) nedeniyle özel işlem gerektirir.

Dolayısıyla, verileri bir Haritaya bağlamak istiyorsanız, kullanmanız gerekecek:

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

Doğrudan ürün serisini nasıl kaldırabilirim ArrayList?


Yanıtlar:


154

TypeReferenceSarmalayıcıyı kullanarak bir listeye doğrudan seriyi kaldırabilirsiniz . Örnek bir yöntem:

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;
}

Ve şu şekilde kullanılır:

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

TipReferans Javadoc


Cevabınız, yerleşik desteğin nasıl kullanılacağına ilişkin bilgileriyle ilgili görünüyor TypeReference- bunu nasıl yapacağımı bilmiyorum ... Lütfen jeneriklerin nasıl kullanılacağına ilişkin talimatları için yukarıdaki düzenlememe bakın.
tacos_tacos_tacos

Eh, ilgili. Ancak bu, üretimde çalışan koddan bir parçacıktır. Karışımınızı unutun, sadece gösterdiğim kodu kullanın (ama POJO'yu tabii ki gerçek fasulye sınıfınızın adıyla değiştirin).
Algılama

Kodunuz derlendi, ancak arrayList.toString()about a NullPointerException. Bunun POJO, özellikleri için doğru adlandırma kurallarına uymamasından kaynaklanabileceğini tahmin ediyorum , yani tüm sorun, web hizmetinin geri dönmesi Prop1Memberve nesnemin sahip olmasıdır Prop1. Başlangıçta mixins kullanmamın tek gerçek nedeni budur, bu nedenle beyanları @JsonPropertysaf nesnelerime koymak zorunda değilim .
tacos_tacos_tacos

1
En azından bir listeyi geri aldığınızdan emin olmak için dizinizi görsel olarak inceleyin. Ve gerekirse, her şeyi düzgün bir şekilde serileştirilmiş hale getirmek için TypeReference ile birlikte çalışması gereken mixini geri ekleyin.
Algı

2
@JsonProperty, insanların da yaptığı kadar kötü değil. Sahadaki mevcut standardizasyon durumu (minimum) ile satıcıya özgü açıklamalardan uzaklaşmak zordur.
Algılama

111

Diğer bir yol da bir diziyi tür olarak kullanmaktır, örneğin:

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

Bu şekilde, Type nesnesiyle ilgili tüm zorluklardan kurtulursunuz ve gerçekten bir listeye ihtiyacınız varsa, diziyi her zaman bir listeye dönüştürebilirsiniz:

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

IMHO bu çok daha okunabilir.

Ve bunu gerçek bir liste haline getirmek için (değiştirilebilir, sınırlamalarına bakın Arrays.asList()) ardından aşağıdakileri yapın:

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

1
Elbette zarif, ancak parametre olarak geçirmek istemediğim MyPojo []. Sınıfından dolayı bunu doğrulayamıyorum.
Adrian Redgers

Bir TypeFactorysonraki cevapta açıklandığı gibi kullanmayı düşünüyorum : stackoverflow.com/a/42458104/91497 , türü belirlemenin Jackson yolu.
Jmini

36

Bu varyant daha basit ve zarif görünüyor.

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

Açık CollectionTypereferans için teşekkürler .
Erwin Wessels

3

Ben de aynı sorunu yaşıyorum. ArrayList'e dönüştürülecek bir json'ım var.

Hesap buna benzer.

Account{
  Person p ;
  Related r ;

}

Person{
    String Name ;
    Address a ;
}

Yukarıdaki sınıfların tümü uygun şekilde notlandırılmıştır. TypeReference> () {} 'ı denedim ama çalışmıyor.

Bana Arraylist verir, ancak ArrayList, son değerleri içeren daha fazla bağlantılı hashmapler içeren bir linkedHashMap'e sahiptir.

Kodum aşağıdaki gibidir:

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;
}

Sonunda sorunu çözdüm. Json String'deki Listeyi aşağıdaki gibi doğrudan ArrayList'e dönüştürebiliyorum:

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 ;
    }  

}

2

Bu benim için çalışıyor.

@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.
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.