Jacksonを使用してJSONをArrayList <POJO>に逆シリアル化する


97

MyPojoJSONから逆シリアル化するJavaクラスがあります。MyPojoDeMixIn逆シリアル化を支援するために、特別なMixInクラスを構成しました。MyPojo唯一持っているintString、適切なゲッターとセッターと組み合わせて、インスタンス変数を。MyPojoDeMixIn次のようになります。

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

私のテストクライアントでは次のようにしていますがJsonMappingException、型の不一致に関連しているため、コンパイル時には機能しません。

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

だけが含まれる「Response」オブジェクトを作成することでこの問題を軽減できることは承知していますArrayList<MyPojo>が、返したいすべての型に対してこれらのやや役に立たないオブジェクトを作成する必要があります。

また、JacksonInFiveMinutesをオンラインで見ましたが、内容Map<A,B>とそれが私の問題にどのように関連しているかを理解するのにひどい時間がありました。わからない場合は、私はJavaにまったく不慣れで、Obj-Cのバックグラウンドを持っています。彼らは特に言及します:

POJOおよび「単純な」タイプへのバインドに加えて、1つの追加のバリアントがあります。それは、ジェネリック(型付き)コンテナーへのバインドのバリアントです。この場合は、いわゆるType Erasure(Javaが下位互換性のある方法でジェネリックを実装するために使用)による特別な処理が必要であり、Collection.class(コンパイルされない)などを使用できません。

したがって、データをマップにバインドする場合は、次のようにする必要があります。

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

に直接デシリアライズするにはどうすればよいArrayListですか?


回答:


149

TypeReferenceラッパーを使用して、リストに直接逆シリアル化できます。メソッドの例:

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

そして、このように使用されます:

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

TypeReference Javadoc


あなたの答えは、組み込みサポートの使用方法に関する情報に関連しているようですTypeReference-方法がわかりません...ジェネリックの使用方法については、上記の編集を参照してください。
tacos_tacos_tacos 2012年

まあ、それは関連しています。しかし、これは本番環境で動作するコードからの抜粋です。ミックスインを忘れて、私が示したコードを使用してください(もちろん、POJOを実際のBeanクラスの名前に置き換えてください)。
認識

コードはコンパイルされましたが、arrayList.toString()aboutを出力しようとするとランタイム例外が発生しますNullPointerException。これはPOJO、そのプロパティの正しい命名規則に準拠していないことが原因であると推測していProp1MemberますProp1。つまり、Webサービスが返され、オブジェクトにが含まれていることが全体の問題です。これが私が最初にミックスインを使用している唯一の本当の理由なので@JsonProperty、純粋なオブジェクトに宣言を入れる必要はありません。
tacos_tacos_tacos

1
配列を視覚的に検査して、少なくともリストが返されていることを確認します。そして必要に応じてミックスインを追加します。これ TypeReferenceと一緒に機能し、すべてを適切にデシリアライズします。
認識

2
@JsonPropertyは、人がそうするほど悪ではありません。現場での標準化(最小限)の現状では、ベンダー固有のアノテーションから逃れることは困難です。
認識

104

別の方法は、配列を型として使用することです。例:

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

このようにして、Typeオブジェクトの手間を省き、リストが本当に必要な場合は、常に次の方法で配列をリストに変換できます。

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

私見これはもっと読みやすいです。

そして、それを実際のリスト(変更可能、の制限を参照Arrays.asList())にするには、次のようにします。

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

1
確かにエレガントですが、パラメーターとして渡したくないMyPojo []。classがあるため、それを生成できません。
エイドリアンレジャース

TypeFactory次の回答で説明されているように使用すると思います:stackoverflow.com/a/42458104/91497は、タイプを指定するためのジャクソンの方法です。
Jmini、

32

このバリアントは、よりシンプルでエレガントに見えます。

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

3

私も同じ問題を抱えています。ArrayListに変換されるjsonがあります。

アカウントはこのようになります。

Account{
  Person p ;
  Related r ;

}

Person{
    String Name ;
    Address a ;
}

上記のクラスはすべて適切に注釈が付けられています。TypeReference>(){}を試しましたが、機能しません。

それは私にArraylistを与えますが、ArrayListには、最終的な値を含むいくつかのリンクされたハッシュマップを含むlinkedHashMapがあります。

私のコードは次のとおりです:

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

ようやく問題を解決しました。次のように、Json Stringのリストを直接ArrayListに変換できます。

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

これでうまくいきます。

@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.
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.