comment jeter à CRTP en java?
Question
J'ai une affaire assez simple où je fais une affectation générique de base:
final Detail detail = field.getAnnotation(Detail.class);
final String example = detail.example();
final Class<?> type = field.getType();
if (List.class.isAssignableFrom(type))
...
else if (Enum.class.isAssignableFrom(type))
setValue(contract, field, Enum.valueOf(type, example));
else if (...)
.....
Enum.valueOf () est un peu difficile d'appeler, dans mon cas, l'erreur est:
valueOf (java.lang.Class, java.lang.String) dans java.lang.Enum ne peut pas être appliquée à (java.lang.Class, java.lang.String)
Cela rend parfaitement logique puisque le type est Class<Object>
. Mais depuis Enum
est CRTP, je ne peux pas trouver un bon moyen de le type transtypée pour le compilateur heureux. Est-ce en utilisant le type brut Enum.valueOf((Class)type, example))
la seule réponse? Il me donne 2 avertissements au lieu d'un seul.
La solution
La ligne suivante fera avec un seul avertissement:
...
setValue( contract, field, Enum.valueOf( type.asSubclass( Enum.class ), example ) );
...
Autres conseils
Vous pouvez écrire une méthode d'aide pour capturer un type « T » qui satisfait l'exigence de Enum:
private <T extends Enum<T>> T helper(Class<?> type, String example) {
return Enum.valueOf((Class<T>)type, example);
}
cela ne devrait avoir un avertissement
et vous pouvez l'utiliser comme
else if (Enum.class.isAssignableFrom(type))
setValue(contract, field, helper(type, example));
Edit: D'accord, alors que diriez-vous:
private <T extends Enum<T>> Object helper(Class<?> type, String example) {
return Enum.valueOf((Class<T>)type, example);
}
Je ne pense pas qu'il est possible de supprimer les avertissements du compilateur
Le meilleur scénario est de réduire toutes les erreurs dans un comme @tangens fait.
trouvé deux sujets du forum qui montrent des réponses infructueuses et explique le pourquoi un peu plus.
- http://forums.sun.com/thread.jspa?threadID=5215278
- http://forums.sun.com/thread.jspa?threadID=694354
Je mis en place un exemple complet pour démontrer la question que je le vois.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.List;
public class Test {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Detail {
String example();
}
public enum ExampleEnum {
FOO_BAR, HELLO_WORLD
}
@Detail(example = "FOO_BAR")
public ExampleEnum test;
public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
populate(new Test());
}
public static void populate(Object o) throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchFieldException {
final Field field = o.getClass().getField("test");
final Detail detail = field.getAnnotation(Detail.class);
System.out.println("Annotation = " + detail);
final String example = detail.example();
final Class<?> type = field.getType();
System.out.println("Field Class = " + type.getName());
if (List.class.isAssignableFrom(type)) {
} else if (Enum.class.isAssignableFrom(type)) {
Class<? extends Enum> enumType = type.asSubclass(Enum.class); // Enum is a raw type. References to generic type Enum<E> should be parameterized
Enum val = Enum.valueOf(enumType, example); // 1) Enum is a raw type. References to generic type Enum<E> should be parameterized
// 2) Type safety: Unchecked invocation valueOf(Class<capture#7-of ? extends Enum>, String) of the generic
// method valueOf(Class<T>, String) of type Enum
field.set(o, val);
}
}
}