À l'aide de Printemps RestTemplate au générique de la méthode avec un paramètre générique
Utilisation de types génériques avec le Printemps RestTemplate nous avons besoin d'utiliser ParameterizedTypeReference
(Impossible d'obtenir un générique ResponseEntity<T> où T est une classe générique "SomeClass<SomeGenericType>")
Supposons que j'ai un peu de classe
public class MyClass {
int users[];
public int[] getUsers() { return users; }
public void setUsers(int[] users) {this.users = users;}
}
Et certaines classe wrapper
public class ResponseWrapper <T> {
T response;
public T getResponse () { return response; }
public void setResponse(T response) {this.response = response;}
}
Donc, si je suis en train de faire quelque chose comme cela, tout est OK.
public ResponseWrapper<MyClass> makeRequest(URI uri) {
ResponseEntity<ResponseWrapper<MyClass>> response = template.exchange(
uri,
HttpMethod.POST,
null,
new ParameterizedTypeReference<ResponseWrapper<MyClass>>() {});
return response;
}
Mais quand j'essaie de créer des génériques variante de la méthode ci-dessus ...
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;
}
... et l'appel de cette méthode comme si ...
makeRequest(uri, MyClass.class)
... au lieu de se ResponseEntity<ResponseWrapper<MyClass>>
objet que je suis ResponseEntity<ResponseWrapper<LinkedHashSet>>
objet.
Comment puis-je résoudre ce problème? Est-il un RestTemplate bug?
Mise à JOUR de 1
Grâce à @Sotirios je comprends le concept. Malheureusement, je suis nouvellement inscrit ici donc je ne peux pas commenter sa réponse, donc de l'écrire ici. Je ne suis pas sûr que j'ai bien compris comment mettre en œuvre l'approche proposée pour résoudre mon problème avec Map
avec Class
clé (Proposé par @Sotirios à la fin de sa réponse). Quelqu'un aurait l'esprit pour donner un exemple?
- Vous devriez toujours être en mesure de commenter sur les réponses à vos questions. La solution proposée fonctionne comme ceci. Vous créez un
Map<Class, ParameterizedTypeReference<ResponseWrapper<?>>>
. Vous ajoutez pré-construitsParameterizedTypeReference
cas pour les types réels que vous vous attendez à laMap
pour le correspondantClass
. - Pouvez-vous reformuler pour quelqu'un qui est nouveau pour le Java? Je suis venue à partir d'un C# arrière-plan, de sorte que cela a été très intéressant pour moi.
Vous devez vous connecter pour publier un commentaire.
Non, il n'est pas un bug. C'est un résultat de comment le
ParameterizedTypeReference
hack fonctionne.Si vous regardez à sa mise en œuvre, il utilise
Class#getGenericSuperclass()
laquelle les étatsDonc, si vous utilisez
il renverra précisément un
Type
pourResponseWrapper<MyClass>
.Si vous utilisez
il renverra précisément un
Type
pourResponseWrapper<T>
parce que c'est la façon dont il apparaît dans le code source.Quand le Printemps voit
T
, qui est en fait unTypeVariable
objet, il ne sait pas le type à utiliser, de sorte qu'il utilise sa valeur par défaut.Vous ne pouvez pas utiliser
ParameterizedTypeReference
la manière que vous proposez, rendant générique dans le sens de l'acceptation de n'importe quel type. Envisager la rédaction d'unMap
avec les principauxClass
mappé à un prédéfiniParameterizedTypeReference
pour la classe.Vous pouvez sous-classe
ParameterizedTypeReference
et de remplacer songetType
méthode pour retourner dûment crééParameterizedType
, comme suggéré par IonSpin.Class
objet pourList<MyClass>
, une telle chose n'existe pas. Il peut y avoir unParameterizedType
pourList<MyClass>
mais vous devez construire vous-même ou utiliser le type de jeton de truc.List<MyClass>
n'existe pas. Depuis leur méthode accepte unClass
argument, ils ne peuvent "nid" un argument de type.TypeReference
à Jackson,ParameterizedTypeReference
dansRestTemplate
, c'est tout de même modèle, appelé type de jeton.Que le code ci-dessous montre, il fonctionne.
Class<T>
paramètre limite la solution à la non-types génériques.Comme Sotirios explique, vous ne pouvez pas utiliser le
ParameterizedTypeReference
, mais ParameterizedTypeReference est uniquement utilisé pour fournirType
à l'objet mappeur, et que vous avez la classe qui est supprimé lorsque le type d'effacement se produit, vous pouvez créer votre propreParameterizedType
et passer àRestTemplate
, de sorte que l'objet de mapper permet de reconstituer l'objet dont vous avez besoin.Vous devez d'abord avoir la ParameterizedType interface implémentée, vous pouvez trouver une application dans Google Gson projet ici.
Une fois que vous l'ajouter à la mise en œuvre de votre projet, vous pouvez étendre le résumé
ParameterizedTypeReference
comme ceci:Et puis vous pouvez passer à votre échange de fonction:
Avec toutes les informations de type objet présent mapper correctement construire votre
ResponseWrapper<MyClass>
objetEn fait, vous pouvez le faire, mais avec un autre code.
Il est Goyave équivalent de ParameterizedTypeReference et il est appelé TypeToken.
Goyave de classe est beaucoup plus puissantes que le Printemps, l'équivalent de l'.
Vous pouvez composer le TypeTokens comme vous le souhaitez.
Par exemple:
Si vous appelez
mapToken(TypeToken.of(String.class), TypeToken.of(BigInteger.class));
vous permettra de créerTypeToken<Map<String, BigInteger>>
!Le seul inconvénient ici est que beaucoup de Printemps Api requièrent
ParameterizedTypeReference
et pasTypeToken
. Mais nous pouvons créerParameterizedTypeReference
de mise en œuvre qui est de l'adaptateur àTypeToken
lui-même.Alors vous pouvez l'utiliser comme ceci:
Et de l'appeler comme:
Et le corps de la réponse sera correctement désérialisé comme
ResponseWrapper<MyClass>
!Vous pouvez même utiliser des types plus complexes si vous réécrivez votre générique de la méthode de requête (ou surcharge) comme ceci:
De cette façon
T
peut être de type complexe, commeList<MyClass>
.Et de l'appeler comme:
Je suis en utilisant org.springframework.de base.ResolvableType pour un ListResultEntity :
Donc dans votre cas:
Cela ne fait qu'utiliser du printemps et de cours nécessite des connaissances sur le retour (mais doit encore travailler pour des choses comme le Wrapper>> tant que les classes comme varargs )
J'ai une autre façon de faire cela... supposons que vous échangez votre message convertisseur de Chaîne pour votre RestTemplate, vous pouvez recevoir les premières JSON. À l'aide de la crue JSON, vous pouvez ensuite la carte dans votre Collection Générique à l'aide d'un Jackson Objet Mappeur. Voici comment:
De changer de message converter:
Puis obtenir votre réponse JSON comme ceci:
Processus de la réponse, comme ceci:
Note: Cette réponse fait référence/ajoute à Sotirios Delimanolis la réponse de commentaire.
J'ai essayé de le faire fonctionner avec
Map<Class, ParameterizedTypeReference<ResponseWrapper<?>>>
, comme indiqué dans Sotirios commentaire, mais je ne pouvais pas sans exemple.En fin de compte, j'ai laissé tomber le masque et la paramétrisation de ParameterizedTypeReference et premières utilisées types au lieu de cela, comme
et ce enfin travaillé.
Si quelqu'un a un exemple avec la paramétrisation, je serais très reconnaissant pour le voir.
Vous pourriez avoir fait comme ci-dessous sans l'aide de classe wrapper lui-même. Essayez d'utiliser la puissance réelle si les génériques