I have a method fetchObjects(String)
that is expected to return an array of Contract
business objects. The className
parameter tells me what kind of business objects I should return (of course this doesn't make sense in this construed case because I already said I will return Contract
s, but it's basically the situation I have in my real scenario). So I get the set of entries from somewhere and load the class of the collection's entries (the type of which is specified by className
).
Now I need to construct the array to return, so I use Set
's toArray(T[])
method. Using reflection, I build myself an empty Contracts array. But, this gives me a value of static type Object
! So next I need to cast it to the appropriate type, which in this case is Contract[]
(see "asterisk-underlined" part in the listing below).
My question is: Is there a way, and how, to cast to Contract[]
as I do in the listing, but determining the type of the array elements (Contract
) only through className
(or entriesType
)? In other words, what I'd like to do is basically casting like this: (entriesType[]) valueWithStaticTypeObject
, where entriesType be replaced by the class specified through the classname
parameter, i.e. Contract
.
Is this somehow inherently impossible, or can it be done somehow? Maybe using generics?
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.
toArray
, taken from CodeIdol, I updated my fetchObjects
method thus:
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;
}
What do I need to do to get rid of the compiler error quoted in the comment? Do I absolutely have to specify Set<Contract>
in the return type of my getEntrySet
method so that this can work? Thanks for any pointers.
You may use the class as the parameter rather then the class name.
static <T extends Contract> T[] buildArray(Class<T> clazz){
ArrayList<T> l=new ArrayList<T>();
return l.toArray((T[]) java.lang.reflect.Array.newInstance(clazz, l.size()));
}
EDIT: (after read Yang comment)
No, You cannot use generic type with the value of a variable.