0

So I am trying to invoke the JUnit Parameterized test runner on a load of individual generic typed objects. The specific classes to be used are known to descendant classes.

Originally I managed to get a method which returns a Collection<T> for JUnit to work with, but then I realised JUnit actually requires a Collection<T[]> - I'm having trouble creating this array because of Java's reluctance/refusal to create arrays of generics.

protected static <T> Collection<T> someMethod(Class<T> someClass)
{
    Collection<T> result = new ArrayList<T>();
    T someBean;
    while (someCondition(...))
    {
        //Do some stuff to compute someBean

        result.add(someBean);
    }
    return result;
}

Now JUnit requires an Collection<T[]> like this:

// (descendant class)
@Parameters
public static Collection<SomeActualClass[]> data()
{
    return someMethod(SomeActualClass.class);
}

So I want to change the return type by doing something like:

protected static <T> Collection<T[]> someMethod(Class<T> someClass)
{
    Collection<T[]> result = new ArrayList<T>();
    T someBean;
    while (someCondition(...))
    {
        //Do some stuff to compute someBean

        result.add(new T[]{someBean});
    }
    return result;
}

Unfortunately Java won't let me do this because you can't create generic arrays.

I'm tempted to put the statement as result.add((T[])new Object[]{someBean}); but is this safe? or is there a better way?

Adam Burley
  • 5,551
  • 4
  • 51
  • 72

2 Answers2

0

It's awkward as hell, but the following should work:

T[] theArray = (T[]) Array.newInstance(someClass, 1);
theArray[0] = someBean;

Cf.:

public class Foo<T> {

    final T t0;
    final T t1;
    final Class theClass;

    public Foo(T t0, T t1, Class<T> theClass) {
        this.t0 = t0;
        this.t1 = t1;
        this.theClass = theClass;
    }

    @SuppressWarnings("unchecked")
    public T[] getStuffArray() {
        T[] theArray = (T[]) Array.newInstance(theClass, 2);
        System.out.println(theArray.getClass().getName());
        theArray[0] = t0;
        theArray[1] = t1;
        return theArray;
    }

    public static void main(String[] args) {

        Number[] stuffArray = new Foo<Number>(1, 2.5, Number.class).getStuffArray();
        for (Number s: stuffArray) {
            System.out.println(s);
        }
    }
}

If you're really really sure that it's safe, you could skip someClass and just use someObject.getClass(), but then you run the risk that someObject is a subclass of T rather than T itself, which in the above case would get you an ArrayStoreException trying to put 2.5 into an Integer[].

(Note though that if you get past that -- if you only store Integers -- java will let you get away with casting that Integer[] to a Number[]. Don't ask me why.)

David Moles
  • 48,006
  • 27
  • 136
  • 235
-1

You can try to use a List<T> and then use the toArray(T[]) method, and you will get a T[].

You can also create a generic List with only one element using Collections.singletonList(T o)

greuze
  • 4,250
  • 5
  • 43
  • 62
  • 2
    Unfortunately these don't help: `toArray()` returns an `Object[]` rather than `T[]` which is identical to `new Object[]{someBean}` as in my example, and `singletonList` returns a `List` rather than an array as expected by JUnit. The one-argument form `toArray(T[])` returns a `T[]` but you still have to create the generic array to pass into the `toArray` method, so it's no help... – Adam Burley Nov 22 '10 at 12:21
  • toArray() returns Object[], toArray(T[]) returns T[] – greuze Feb 06 '13 at 08:42