1. ホーム
  2. java

ジェネリックメソッドでSpring RestTemplateをジェネリックパラメータで使用する

2023-10-01 21:42:20

質問

Spring RestTemplateでジェネリックタイプを使用するためには ParameterizedTypeReference ( Unable to get a generic ResponseEntity<T> where T is a generic class "SomeClass<SomeGenericType> ".ここで、Tはジェネリッククラスです。 )

あるクラスがあるとします。

public class MyClass {
    int users[];

    public int[] getUsers() { return users; }
    public void setUsers(int[] users) {this.users = users;}
}

そして、いくつかのラッパークラス

public class ResponseWrapper <T> {
    T response;

    public T getResponse () { return response; }
    public void setResponse(T response) {this.response = response;}
}

という感じで、こんな感じでやっていれば万事OKです。

public ResponseWrapper<MyClass> makeRequest(URI uri) {
    ResponseEntity<ResponseWrapper<MyClass>> response = template.exchange(
        uri,
        HttpMethod.POST,
        null,
        new ParameterizedTypeReference<ResponseWrapper<MyClass>>() {});
    return response;
}

しかし、上記のメソッドのジェネリックバリアントを作ろうとすると ...

public <T> ResponseWrapper<T> makeRequest(URI uri, Class<T> clazz) {
   ResponseEntity<ResponseWrapper<T>> response = template.exchange(
        uri,
        HttpMethod.POST,
        null,
        new ParameterizedTypeReference<ResponseWrapper<T>>() {});
    return response;
}

... そして、このメソッドを以下のように呼び出します。

makeRequest(uri, MyClass.class)

... 代わりに ResponseEntity<ResponseWrapper<MyClass>> オブジェクトを取得します。 ResponseEntity<ResponseWrapper<LinkedHashSet>> オブジェクトが表示されます。

この問題を解決するにはどうすればよいですか?それはRestTemplateのバグですか?

アップデイト1 Sotiriosのおかげでコンセプトが理解できました。残念ながら、私はここに新しく登録したので、彼の答えにコメントできないので、ここに書きます。私は私の問題を解決するために提案されたアプローチを実装する方法を明確に理解していることを確信していません。 MapClass キー(彼の答えの最後で@Sotiriosによって提案された)。誰かが例を与えることを気にしますか?

どのように解決するのですか?

いいえ、バグではありません。これは ParameterizedTypeReference ハックが機能する結果です。

その実装を見てみると Class#getGenericSuperclass() という記述があります。

このクラスが表現する実体 (クラス、インターフェース、プリミティブ型、またはvoid)の直接のスーパークラスを表す型を返します。

スーパークラスがパラメタライズドタイプである場合。 Type オブジェクトが返されます。 は、ソースコードで使われた実際の型パラメータを正確に反映したものでなければなりません。 を正確に反映していなければなりません。

ということは、もしあなたが

new ParameterizedTypeReference<ResponseWrapper<MyClass>>() {}

を返すと、正確に Type に対して ResponseWrapper<MyClass> .

を使用する場合

new ParameterizedTypeReference<ResponseWrapper<T>>() {}

を返すと、正確に Type に対して ResponseWrapper<T> というのは、ソースコードにそのように表示されるからです。

Springが T を見ると、それは実際には TypeVariable オブジェクトであり、使用する型を知らないので、デフォルトを使用します。

を使うことはできません。 ParameterizedTypeReference をどのような型でも受け入れるという意味で一般的にすることはできません。を書くことを考えましょう。 Map をキーとして Class は、あらかじめ定義された ParameterizedTypeReference にマップされます。

をサブクラス化することができます。 ParameterizedTypeReference をオーバーライドし、その getType メソッドをオーバーライドして、適切に作成された ParameterizedType , IonSpinが提案したように .