Tengo un método fetchObjects(String)
que se espera que devuelva una matriz de Contract
objetos comerciales. El parámetro className
me dice qué tipo de objetos comerciales debo devolver (por supuesto, esto no tiene sentido en este caso interpretado porque ya dije que devolveré Contract
s, pero básicamente es la situación que tengo en mi situación real). Así que obtengo el conjunto de entradas de algún lugar y cargo la clase de las entradas de la colección (cuyo tipo está especificado en className
).Transmisión a una clase que se determina en tiempo de ejecución
Ahora necesito construir la matriz para devolver, entonces uso el método Set
toArray(T[])
. Usando la reflexión, me construyo una matriz de Contratos vacía. Pero, esto me da un valor de tipo estático Object
! Así que, a continuación, tengo que convertirlo al tipo apropiado, que en este caso es Contract[]
(ver la parte "asterisco subrayado" en el listado a continuación).
Mi pregunta es: ¿Hay alguna manera, y cómo, para echar a Contract[]
como lo hago en el perfil, pero determinar el tipo de los elementos de la matriz (Contract
) sólo a través de className
(o entriesType
)? En otras palabras, lo que me gustaría hacer es básicamente transmitir de esta forma: (entriesType[]) valueWithStaticTypeObject
, donde entriesType se reemplaza por la clase especificada a través del parámetro classname
, es decir, Contract
.
¿Es esto de alguna manera inherentemente imposible, o se puede hacer de alguna manera? Tal vez usando genéricos?
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
}
}
Thanks.
Actualización: Utilizando el método de tipo seguro
toArray
, tomada de
CodeIdol, he actualizado mi
fetchObjects
método así:
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;
}
¿Qué necesito hacer para deshacerse del error del compilador citado en el comentario? ¿Tengo que especificar absolutamente Set<Contract>
en el tipo de devolución de mi método getEntrySet
para que esto pueda funcionar? Gracias por cualquier puntero.
¿Cómo se maneja cuando la clase entriesType no es una subclase de Contrato? –
entriesType es * no * necesariamente un subtipo de Contrato. Podría ser Pet, Friend, Hobby, cualquier cosa de la que tengas una colección. En mi caso de ejemplo, un Cliente tendría una colección de Contratos. –