J'ai une méthode fetchObjects(String)
qui devrait renvoyer un tableau de Contract
objets métier. Le paramètre className
me dit quel type d'objets métier je devrais retourner (bien sûr cela n'a pas de sens dans ce cas, car j'ai déjà dit que je vais retourner Contract
s, mais c'est essentiellement la situation que j'ai dans mon scénario réel). Donc, je reçois l'ensemble des entrées de quelque part et charge la classe des entrées de la collection (dont le type est spécifié par className
).Coulée vers une classe qui est déterminée au moment de l'exécution
Maintenant, j'ai besoin de construire le tableau à retourner, donc j'utilise la méthode toArray(T[])
de Set
. En utilisant la réflexion, je me construis un tableau de contrats vide. Mais, cela me donne une valeur de type statique Object
! Donc, je dois ensuite le mouler au type approprié, qui dans ce cas est Contract[]
(voir la partie «souligné par un astérisque» dans la liste ci-dessous).
Ma question est: Est-il possible, et comment, de caster Contract[]
comme je le fais dans la liste, mais déterminer le type des éléments du tableau (Contract
) que par className
(ou entriesType
)? En d'autres termes, ce que je voudrais faire est essentiellement de lancer comme ceci: (entriesType[]) valueWithStaticTypeObject
, où entriesType est remplacé par la classe spécifiée par le biais du paramètre classname
, c'est-à-dire Contract
. Est-ce que c'est en quelque sorte intrinsèquement impossible, ou peut-il être fait d'une manière ou d'une autre? Peut-être en utilisant des génériques?
package xx.testcode;
import java.util.HashSet;
import java.util.Set;
class TypedArrayReflection {
public static void main(String[] args) {
try {
Contract[] contracts = fetchObjects("Contract");
System.out.println(contracts.length);
} catch (ClassNotFoundException e) {}
}
static Contract[] fetchObjects(String className) throws ClassNotFoundException {
Class<?> entriesType = Class.forName("xx.testcode."+className);
Set<?> entries = ObjectManager.getEntrySet(className);
return entries.toArray(
(Contract[]) java.lang.reflect.Array.newInstance(
/********/ entriesType, entries.size()));
}
}
class Contract { } // business object
class ObjectManager {
static Set<?> getEntrySet(String className) {
if (className.equals("Contract"))
return new HashSet<Contract>();
return null; // Error
}
}
Merci.
Mise à jour: En utilisant la méthode de type sécurisé
toArray
, pris de
CodeIdol, je mis à jour ma méthode
fetchObjects
ainsi:
static Contract[] fetchObjects(String className) throws ClassNotFoundException {
Class<?> entriesType = Class.forName("xx.testcode."+className);
Set<?> entries = ObjectManager.getEntrySet(className);
return toArray(entries, entriesType); // compile error
// -> "method not applicable for (Set<capture#3-of ?>, Class<capture#4-of ?>)"
}
public static <T> T[] toArray(Collection<T> c, Class<T> k) {
T[] a = (T[]) java.lang.reflect.Array.newInstance(k, c.size());
int i = 0;
for (T x : c)
a[i++] = x;
return a;
}
Que dois-je faire pour se débarrasser de l'erreur du compilateur cité dans le commentaire? Dois-je absolument spécifier Set<Contract>
dans le type de retour de ma méthode getEntrySet
pour que cela fonctionne? Merci pour les pointeurs.
Comment gérer lorsque la classe entriesType n'est pas une sous-classe de Contract? –
entriesType n'est pas un sous-type de Contract. Ce pourrait être Pet, Friend, Hobby - tout ce que vous pourriez avoir une collection de. Dans mon exemple, un client aurait une collection de contrats. –