web-dev-qa-db-fra.com

Java generics: récupère la classe du type de retour de la méthode générique

Contexte

J'ai écrit une fois cette méthode:

private <T> SortedSet<T> createSortedSet() {
  return new TreeSet<T>();
}

Il est censé être appelé comme ceci:

Set<String> set = createSortedSet();

Cela fonctionne bien (bien que j'aie vu dans les réponses ici lors de la recherche de la question actuelle que cela est sujet aux erreurs).

La situation présente

Quoi qu'il en soit, j'écris maintenant le code suivant (dans une classe qui étend javax.servlet.jsp.tagext.TagSupport):

private <T> T evaluate(String expression) {
  ExpressionEvaluator evaluator = pageContext.getExpressionEvaluator();
  return evaluator.evaluate(expression, T, null, pageContext.getVariableResolver());
}

Le but est de pouvoir appeler ça comme:

Integer width = evaluate(widthStr);

Le code de ma méthode d'évaluation ne fonctionne évidemment pas. Le deuxième argument de evaluator.evaluate() est censé être un objet Class. Cela m'amène à:

Ma question

Comment puis-je obtenir la classe d'un type générique (retour)? Que dois-je écrire à la place de T comme deuxième argument à évaluer?

EDIT: Conclusion

Nicolas semble avoir raison, cela ne peut pas être fait et je dois passer la classe comme argument à ma méthode. L'avantage est que, puisque sa solution rend l'argument paramétré sur le type générique, j'obtiens un contrôle de compilation sur cet argument.

33
Peter Jaric

Malheureusement, vous devrez certainement changer votre méthode pour:

private <T> T evaluate(Class<T> clazz, String expression)

puis passez clazz comme deuxième paramètre. Pas aussi court que prévu.

47
Nicolas

Vous pouvez d'abord créer un objet générique puis récupérer son type paramétré:

private <T> T evaluate(String expression) {
  List<T> dummy = new ArrayList<>(0);
  Type[] actualTypeArguments = ((ParameterizedType) dummy.getClass().getGenericSuperclass()).getActualTypeArguments();
  Type clazz = actualTypeArguments[0];
  Class<T> theClass = (Class<T>) clazz.getClass();

  ExpressionEvaluator evaluator = pageContext.getExpressionEvaluator();
  return evaluator.evaluate(expression, theClass, null, pageContext.getVariableResolver());
}

Il faut se méfier! Vous n'avez pas de Class<> objet, vous obtenez un objet de sous-classe TypeVariableImpl, qui peut se comporter différemment.

0
Fabrice TIERCELIN