Mit Spring RestTemplate in generische Methode mit der generischen parameter
Verwendung generischer Typen mit Feder RestTemplate brauchen wir ParameterizedTypeReference
(Nicht erhalten Sie eine Allgemeine ResponseEntity<T>, wo T ist eine generische Klasse "SomeClass<SomeGenericType>")
Denke, ich habe einige Klasse
public class MyClass {
int users[];
public int[] getUsers() { return users; }
public void setUsers(int[] users) {this.users = users;}
}
Sowie einige wrapper-Klasse
public class ResponseWrapper <T> {
T response;
public T getResponse () { return response; }
public void setResponse(T response) {this.response = response;}
}
Also, wenn ich versuche, so etwas zu tun, ist alles OK.
public ResponseWrapper<MyClass> makeRequest(URI uri) {
ResponseEntity<ResponseWrapper<MyClass>> response = template.exchange(
uri,
HttpMethod.POST,
null,
new ParameterizedTypeReference<ResponseWrapper<MyClass>>() {});
return response;
}
Aber wenn ich versuche zu erstellen, die generische Variante der oben beschriebenen Methode ...
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;
}
... und Sie diese Methode aufrufen, wie so ...
makeRequest(uri, MyClass.class)
... anstatt ResponseEntity<ResponseWrapper<MyClass>>
Objekt ich bin immer ResponseEntity<ResponseWrapper<LinkedHashSet>>
Objekt.
Wie kann ich dieses problem lösen? Ist es ein RestTemplate bug?
UPDATE 1
Dank @Sotirios ich das Konzept zu verstehen. Leider bin ich neu hier angemeldet so kann ich nicht kommentieren, seine Antwort, so schreibt es hier. Im nicht sicher, ob ich klar zu verstehen, wie die Umsetzung der vorgeschlagenen Ansatz um mein problem zu lösen mit Map
mit Class
Schlüssel (Vorgeschlagen von @Sotirios am Ende seiner Antwort). Würde jemand Verstand, um ein Beispiel zu geben?
Map<Class, ParameterizedTypeReference<ResponseWrapper<?>>>
. Fügen Sie pre-konstruiert ParameterizedTypeReference
Instanzen für die eigentlichen Typen, die Sie erwarten, dass die Map
für die entsprechenden Class
.Können Sie formulieren für jemanden, der neu für Java? Ich komme aus der C# - hintergrund, das war also eine sehr interessante Erfahrung für mich.
InformationsquelleAutor Artyom Kozhemiakin | 2014-02-24
Du musst angemeldet sein, um einen Kommentar abzugeben.
Nein, es ist kein bug. Es ist ein Ergebnis, wie die
ParameterizedTypeReference
hack funktioniert.Wenn Sie Blick auf seine Umsetzung, es nutzt
Klasse#getGenericSuperclass()
die StaatenSo, wenn Sie
wird es genau Rückgabe eines
Type
fürResponseWrapper<MyClass>
.Wenn Sie
wird es genau Rückgabe eines
Type
fürResponseWrapper<T>
denn das ist, wie es scheint, in den source-code.Wenn der Frühling sieht
T
, das ist eigentlich einTypeVariable
Objekt, es weiß nicht, den Typ zu verwenden, also verwendet es die Standardeinstellungen.Können Sie nicht verwenden
ParameterizedTypeReference
die Weise, die Sie vorschlagen, so dass es generische in dem Sinne der Annahme einer Typ. Prüfen, schreiben eineMap
mit SchlüsselClass
zugeordnet, der eine vordefinierteParameterizedTypeReference
für die Klasse.Können Sie eine Unterklasse
ParameterizedTypeReference
und überschreiben Sie diegetType
Methode zum zurückgeben einer entsprechend erstelltParameterizedType
, wie vorgeschlagen, durch IonSpin.Auch, was ist der Nachteil für diese Antwort(stackoverflow.com/a/41629503/3656056) Es funktioniert gut für CustomObject<T> aber fehl CustomObject<List<T>>
Es gibt keine
Class
Objekt fürList<MyClass>
eine solche Sache nicht existiert. Es kann einParameterizedType
fürList<MyClass>
aber Sie, die entweder zu konstruieren oder sich selbst mit dem type-token-trick.Diese Lösung scheitert aus dem gleichen Grund Ihren Versuch,
List<MyClass>
existiert nicht. Da Ihre Methode akzeptiert einClass
argument, Sie können nur "nest", eine Art argument.Meinst du TypeToken trick von Gson ?
InformationsquelleAutor Sotirios Delimanolis
Wie der folgende code zeigt, es funktioniert.
In der Tat ist dies die beste/einfachste Antwort, die ich bisher gesehen habe. Sie brauchen nur zu verwenden die MyParameterizedTypeImpl wie gezeigt, und Sie brauchen nicht die statische Karte mit den tatsächlichen Typen und Wrapper-Typ. Natürlich muss die Klasse übergeben, in der Methode oder eines Konstruktors.
Hallo,vielen Dank für deine Antwort, es funktioniert für CustomObject<T> aber es nicht für CustomObject<List<T>> könnten Sie mir bitte helfen um das Problem zu beheben für CustomObject<List<T>>
Diese Antwort ist schlecht erklärt, und die Lösung ist begrenzt. Die Tatsache, dass Sie eine
Class<T>
parameter Grenzen Sie die Lösung, um nicht-generische Typen.InformationsquelleAutor 김원겸
Als Sotirios erklärt, Sie nicht verwenden können, die
ParameterizedTypeReference
, aber ParameterizedTypeReference wird nur verwendet, um bietenType
auf das Objekt-mapper, und als Sie die Klasse, die entfernt wird, wenn die type erasure passiert, können Sie erstellen Sie Ihre eigenenParameterizedType
und pass aufRestTemplate
, so dass das Objekt mapper nachvollziehen können das Objekt, das Sie brauchen.Zuerst müssen Sie die ParameterizedType-Schnittstelle implementiert, können Sie finden eine Umsetzung in die Google-Gson Projekt hier.
Nachdem Sie die Umsetzung Ihres Projektes, können Sie erweitern die abstrakte
ParameterizedTypeReference
wie diese:Und dann kann passieren, dass auf Ihrem exchange-Funktion:
Mit aller Art von Informationen vorhanden Objekt-mapper korrekt zu erstellen Sie Ihre
ResponseWrapper<MyClass>
ObjektIch kopierte die ParametrizedTypeImpl Umsetzung von Google-Gson-Projekt, der link ist in der Antwort, und auch hier wieder code.google.com/p/google-gson/source/browse/trunk/gson/src/main/... 🙂
Ah, sorry, du hast vollkommen Recht. Dank einem Haufen! 🙂
Auch die ParameterizedTypeImpl-Klasse im JDK hat einen privaten Konstruktor, weil sein soll als ein singleton. Die API verfügt über die Methode, die Sie verwenden können, um eine ParameterizedType.
InformationsquelleAutor IonSpin
Tatsächlich, Sie können dies tun, aber mit dem zusätzlichen code.
Es ist Guave äquivalent ParameterizedTypeReference und es heißt TypeToken.
Guave s-Klasse ist viel mächtiger dann der Frühling entspricht.
Komponieren Sie die TypeTokens, wie Sie es wünschen.
Zum Beispiel:
Wenn Sie anrufen
mapToken(TypeToken.of(String.class), TypeToken.of(BigInteger.class));
erstellen SieTypeToken<Map<String, BigInteger>>
!Der einzige Nachteil hier ist, dass viele Spring-APIs erfordern
ParameterizedTypeReference
und nichtTypeToken
. Aber wir können erstellenParameterizedTypeReference
Implementierung-adapterTypeToken
selbst.Dann können Sie es verwenden, wie diese:
Und nennen mag:
- Und der response-body wird korrekt deserialisiert als
ResponseWrapper<MyClass>
!Können Sie auch mit komplexeren Typen, wenn Sie schreiben Sie Ihre generic request-Methode (oder überlastung) wie diese:
Diese Weise
T
werden können, die komplexe Art, wieList<MyClass>
.Und nennen mag:
InformationsquelleAutor Ruslan Stelmachenko
Habe ich eine andere Möglichkeit, dies zu tun... nehme an, Sie tauschen Ihre Nachricht-zu-String-Konverter für Ihre RestTemplate, dann erhalten Sie rohen JSON. Mit dem rohen JSON, können Sie ordnen Sie es in die Generische Collection mit einem Jackson-Objekt-Mapper. Hier ist, wie:
Swap-message converter:
Dann bekommen Sie Ihre JSON-Antwort wie diese:
Prozess der Reaktion, wie diese:
der ObjectMapper die Fabrik constructCollectionType-Methode hat zwei Eingänge, die erste ist eine Collection-Klasse, die zweite (die ich beschriftet mit "clazz") ist die Klasse der Objekte in der oben genannten Sammlung Klasse.
InformationsquelleAutor Dilettante44
Ich bin mit org.springframework.core.ResolvableType für eine ListResultEntity :
Also in deinem Fall:
Dieser macht nur Gebrauch von Feder und erfordert natürlich einige Kenntnisse über die zurückgegebenen Typen (sollte aber auch funktionieren für Dinge wie Wrapper>> so lange, wie Sie die Klassen, die als varargs )
InformationsquelleAutor Justin
Hinweis: Diese Antwort bezieht sich/fügt Sotirios Delimanolis Antwort und Kommentar.
Habe ich versucht es zum laufen zu bringen mit
Map<Class, ParameterizedTypeReference<ResponseWrapper<?>>>
wie in Sotirios Kommentar, konnte aber nicht ohne Beispiel.Am Ende, ließ ich die wildcard und Parametrierung von ParameterizedTypeReference und roh Arten statt, wie so
und dies schließlich funktionierte.
Wenn jemand ein Beispiel mit Parametrierung, wäre ich sehr dankbar, um es zu sehen.
InformationsquelleAutor Ginkobonsai
Hätte man es getan, wie unten, ohne Verwendung von wrapper-Klasse selbst. Versuchen, die wirkliche macht, wenn Generika
InformationsquelleAutor Khader M A