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 Contracts, 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.
Update: Using the type-safe method 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.
EDIT: (after read Yang comment)
No, You cannot use generic type with the value of a variable.