Il est vrai que Java efface types à runtime (transformant ainsi List<String>
en List
), dans la plupart des cas, il stocke le type générique en cours d'exécution, ce qui vous permet de restaurer les informations perdues lors de l'effacement. Vous pouvez récupérer les types génériques réels pour ces:
- arguments de méthode (votre cas)
- types de retour de la méthode
- types de terrain
- super classes/interfaces
Cela signifie que si vous avez simplement un objet de type Liste, il n'y a rien que vous pouvez faire pour obtenir son type générique (object.getClass()
vous obtiendrez List
et c'est tout) - il a été pe Manifestement perdu. Mais, si vous essayez de comprendre le type générique pour un argument de méthode ou l'un de ce qui précède, vous pouvez en utilisant la réflexion. En tant que votre cas ne comporte pas de variables ou d'autres complications, il est assez simple de type pour obtenir le type réel:
ParameterizedType listArgument = (ParameterizedType) ClassDeclaringFoo.class.getMethod("foo", List.class).getGenericParameterTypes()[0];
Type listType = listArgument.getActualTypeArguments()[0]; //This will be a Class representing String, the type of the List
Si vous aviez un plusieurs paramètres et une carte à la place:
public String foo(Object bar, Map<String, Number> possibleFoos) { ... }
Le code renverrait être similaire:
ParameterizedType mapArgument = (ParameterizedType) ClassDeclaringFoo.class.getMethod("foo", Object.class, Map.class).getGenericParameterTypes()[1]; //1 is the index of the map argument
Type keyType = mapArgument.getActualTypeArguments()[0]; //This will be a Class representing String, the type of the Map key
Type valType = mapArgument.getActualTypeArguments()[1]; //This will be a Class representing Number, the type of the Map value
Il est sûr de supposer que c'est ce que DWR utilise aussi bien, car les types sont des arguments de la méthode.
méthodes similaires sont disponibles pour d'autres cas énumérés:
Class.getMethod(...).getGenericReturnType()
vous obtiendrez le type réel de retour
Class.getField(fieldName).getGenericType()
vous obtiendrez le vrai type du champ
Class.getGenericSuperClass()
vous obtiendrez le vrai super tapez
Class.getGenericInterfaces()
vous obtiendrez les types d'interface réelle
Des méthodes équivalentes existent permettant l'accès à AnnotatedType
(type générique ainsi que des annotations sur l'utilisation du type) introduit en Java 8:
Class.getMethod(...).getAnnotatedParameterTypes()
Class.getMethod(...).getAnnotatedReturnType()
Class.getField(fieldName).getAnnotatedType()
Class.getAnnotatedSuperClass()
Class.getAnnotatedInterfaces()
Maintenant, tout cela est dandy lorsque votre cas est aussi simple que dans l'exemple. Mais, imaginez si votre exemple ressemblait à ceci:
public T foo(List<T> possibleFoos) {...}
Dans ce cas, getGenericParameterTypes()[0].getActualTypeArguments()[0]
vous donnerait T
ce qui est plutôt inutile. Pour résoudre ce que T
signifie, vous devez regarder dans la définition de classe, et peut-être super classes, tout en gardant une trace de la façon dont les variables de type sont nommés dans chaque classe, car les noms pourraient être différents dans chacun.
Pour rendre le travail avec la réflexion de type générique plus facile, vous pouvez utiliser une merveilleuse bibliothèque appelée GenTyRef qui fait le travail pour vous, et si vous avez besoin d'aide pour AnnotatedType
s, vous pouvez utiliser ma fourchette appelé GeAnTyRef (les deux sont dans Maven Central). Ils incluent également une fabrique de types, qui vous permet de construire des instances de (Annotated)Type
, ce que vous ne pouvez pas faire facilement en utilisant l'API Java normale. Il existe également une implémentation pratique super type token vous permettant d'obtenir un littéral (Annotated)Type
.
Avec ceux-ci, vous pouvez tout faire avec des types génériques Java permet sans les tracas je l'ai expliqué ci-dessus:
GenericTypeReflector#getExactParameterTypes(...)
GenericTypeReflector#getExactReturnType(...)
GenericTypeReflector#getExactFieldType(...)
GenericTypeReflector#getExactSuperType(...)
Et beaucoup plus d'opérations, comme figuri ng out si un Type
est un super type d'un autre (similaire à Class#isAssignableFrom
mais pour les types génériques), résolvant des variables de type spécifiques, etc.
Merci pour votre réponse complète, c'est exactement ce que je voulais savoir! – Radim
J'ai utilisé la version "hassle" et cela fonctionne très bien pour la liste, mais cela ne fonctionne pas pour map, car getParameterizedType retourne l'objet class.Depuis que j'ai un meilleur aperçu de votre post précédent, j'ai essayé de chercher à nouveau comment utiliser la carte, mais je n'ai rien trouvé. Pouvez-vous m'aider une fois de plus s'il vous plaît? – Radim
@Radim J'ai mis à jour ma réponse pour inclure un exemple qui a une carte comme deuxième argument. C'est ce que vous recherchez? –
kaqqao