web-dev-qa-db-ja.com

Spring / json:List <MyPojo>のような型付きコレクションを変換する

私はリストをマーシャリングしようとしています:_List<Pojo>_オブジェクトをSpring Restテンプレート経由で。

単純なPojoオブジェクトを渡すことができますが、_List<Pojo>_オブジェクトを送信する方法を説明したドキュメントが見つかりません。

Springは、Jackson JSONを使用してHttpMessageConverterを実装しています。ジャクソンのドキュメントはこれをカバーします:

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

したがって、データを_Map<String,User>_にバインドする場合は、以下を使用する必要があります。

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

ここで、TypeReferenceは、(この場合は任意の内部クラスを介して)ジェネリック型定義を渡す場合にのみ必要です。重要な部分は、バインドする型を定義する_<Map<String,User>>_です。

これはSpringテンプレートで実現できますか?私はコードをちらっと見て、それは私に何かをさせませんが、たぶん私はいくつかのトリックを知らないだけです。


ソリューション

以下の役立つ回答のおかげで、最終的な解決策は、リストを送信するのではなく、単に_class PojoList extends ArrayList<Pojo>_などのリストを拡張する単一のオブジェクトを送信することでした。 Springはこのオブジェクトを正常にマーシャリングでき、_List<Pojo>_を送信するのと同じことを実現しますが、ソリューションのクリーン度は少し低くなります。また、春にJIRAを投稿して、HttpMessageConverterインターフェースでこの欠点に対処できるようにしました。

33
David Parks

docs for MappingJacksonHttpMessageConverter を読んだ場合、MappingJacksonHttpMessageConverterのサブクラスを作成して登録し、 getJavaType(Class<?>)をオーバーライドする必要があります。 メソッド:

特定のクラスのJackson JavaTypeを返します。デフォルトの実装はTypeFactory.type(Java.lang.reflect.Type)を返しますが、カスタムジェネリックコレクションの処理を可能にするために、サブクラスでオーバーライドできます。例えば:

protected JavaType getJavaType(Class<?> clazz) {
   if (List.class.isAssignableFrom(clazz)) {
     return TypeFactory.collectionType(ArrayList.class, MyBean.class);
   } else {
     return super.getJavaType(clazz);
   }
}
10

Spring 3.2 では、RestTemplateで新しいexchange()- methodsを使用したジェネリック型がサポートされるようになりました。

 ParameterizedTypeReference<List<MyBean>> typeRef = new ParameterizedTypeReference<List<MyBean>>() {};
 ResponseEntity<List<MyBean>> response = template.exchange("http://example.com", HttpMethod.GET, null, typeRef);

魅力的な作品!

40
oehmiche

ジェネリック型パラメーターが確実に含まれるようにする1つの方法は、実際にListまたはMap型をサブクラス化して、次のようなものにすることです。

static class MyStringList extends ArrayList<String> { }

そのリストのインスタンスを返します。

では、なぜこれが違いを生むのでしょうか?ジェネリック型情報が保持されるのは、メソッドとフィールドの宣言、およびスーパー型の宣言の2か所だけだからです。したがって、「raw」リストにはランタイムタイプ情報が含まれていませんが、「MyStringList」のクラス定義には、スーパータイプ宣言が含まれています。見かけ上型付けされた変数への割り当ては役に立たないことに注意してください。それは、コンパイル時の構文上のシュガーを作成するだけです。実際の型情報は、Classインスタンス(または、Jacksonの場合のJavaTypeやTypeReferenceなどのlibが提供する拡張機能)でのみ渡されます。

これ以外に、JacksonにJavaTypeまたはTypeReferenceを渡して値を渡す方法を理解する必要があります。

23
StaxMan