How to Solve the "A Generic Array of T Is Created for a Varargs Parameter" Compiler Warning

Is it possible to solve the A generic array of T is created for a varargs parameter compiler warning?

In Java 6, other than adding @SuppressWarnings("unchecked"), I don't think so.

This bug report has more information but it boils down to the compiler not liking arrays of generic types.

Solution to compiler warning for generic varargs

Here's my thoughts.

public static interface Foo extends Serializable, Comparable<Object> {
}

public static void main(String[] args) {
// Problem: Unsafe: varargs has generic type
implicitList("1", 2, BigDecimal.valueOf(3.5)); // warning: generic vararg

// Solution 1: Constrain type of varags explicitly through generics
explicitList1(Object.class, "1", 2, BigDecimal.valueOf(3.5));
// However, we could still have the same error from problem
explicitList1(Foo.class, "1", 2, BigDecimal.valueOf(3.5)); // warning: generic vararg
// Fix: Make containing class to exact type (PECS) an array is both producer and consumer
explicitList2(Foo.class, "1", 2, BigDecimal.valueOf(3.5)); // error: incompatible args

// Solution 2: Override varargs by passing array
implicitList(new Object[] { "1", 2, BigDecimal.valueOf(3.5) });
}

private static <T> List<T> explicitList1(Class<? extends T> klass, T... items) {
return Arrays.asList(items);
}

private static <T> List<T> explicitList2(Class<T> klass, T... items) {
return Arrays.asList(items);
}

private static <T> List<T> implicitList(T... items) {
return Arrays.asList(items);
}

Java: Type safety : A generic array of A is created for a varargs parameter

All you can really do is suppress that warning with @SuppressWarnings("unchecked"). Java 7 will eliminate that warning for client code, moving it to the declaration of foo(A... a) rather than the call site. See the Project Coin proposal here.

Java unchecked: unchecked generic array creation for varargs parameter

As janoh.janoh mentioned above, varargs in Java is just a syntactic sugar for arrays plus the implicit creation of an array at the calling site. So

List<List<String>> combinations =
Utils.createCombinations(cocNumbers, vatNumbers, ibans);

is actually

List<List<String>> combinations =
Utils.createCombinations(new List<String>[]{cocNumbers, vatNumbers, ibans});

But as you may know, new List<String>[] is not allowed in Java, for reasons that have been covered in many other questions, but mainly have to do with the fact that arrays know their component type at runtime, and check at runtime whether elements added match its component type, but this check is not possible for parameterized types.

Anyway, rather than failing, the compiler still creates the array. It does something similar to this:

List<List<String>> combinations =
Utils.createCombinations((List<String>[])new List<?>[]{cocNumbers, vatNumbers, ibans});

This is potentially unsafe, but not necessarily unsafe. Most varargs methods simply iterate over the varargs elements and read them. In this case, it doesn't care about the runtime type of the array. This is the case with your method. Since you are on Java 7, you should add the @SafeVarargs annotation to your method, and you won't get this warning anymore. This annotation basically says, this method only cares about the types of the elements, not the type of the array.

However, there are some varargs methods that do use the runtime type of the array. In this case, it is potentially unsafe. That's why the warning is there.

Warning: A generic array of Object&Serializable&Comparable? is created for a varargs parameter

The class Object and the interfaces Comparable and Serializable are the supertypes that the classes Integer and String have in common.

Due to type erasure in generics and covariance of arrays, Generics and arrays don't mix very well with each other. The method Arrays#asList takes a varargs as input, and in Java, varargs are internally implemented with arrays. Hence the warning. (You can read more about this in Josh Bloch's Effective Java.)

Now coming to your second question, <Object & Comparable<Whatever> & Serializable> can be used in method signatures to specify the constraints on type parameters. (See this answer.) Java however does not allow such types in generic type annotations.

In other words, the following is valid:

public static void <A extends Comparable<A> & Serializable> meth(A a);

but the following is not:

List<Serializable & SomeOtherInterface> list = ...;

Warning for generic varargs

To pass the arguments to a varargs method the compiler will place the arguments into an array.

The warning is to let you know that the compiler cannot guarantee that each of the elements in the array - each of the arguments to the varags method - is truly a Map<String, Object>.

This is a bit of an annoying warning because there is no way you can work around this, other than to redefine the method signature to not use varargs. IMO it is safe to ignore as long as you are pretty sure of the actual run-time types of these arguments (which in this case, you are).

IntelliJ warning: Unchecked generics array creation for varargs parameter

A better way to accomplish that would probably be:

when(someService.someMethod(id)).thenThrow(new AccountNotFoundException());

then the compiler should infer the type correctly.

If someService.someMethod(id) has return type void you can do:

doThrow(new AccountNotFoundException()).when(someService).someMethod(id);

Please refer to the official Mockito documentation for examples like this using thenThrow. The documentation is very clear on this point.

You can also check the following StackOverflow question which is very similar (if not an exact duplicate):

How to mock and assert a thrown exception

Unchecked generic array creation for varargs parameter of type Matcher ? extends String [] warning using CoreMatchers.allOf()

If this is Java 7+, then the library you're using can annotate the method with @SafeVarargs. However, this is not under your control.

Otherwise there is no way to avoid an unchecked warning with this method, because the method fundamentally requires an array of a parameterized type, and it is impossible to obtain a non-null value of this type without an unchecked operation somewhere (either in your method or some other method that you call).

Or, looking at the documentation for CoreMatchers, it seems that you could consider using the alternate overload of the allOf, which takes an Iterable of matchers instead. That you can use without unchecked operations.



Related Topics



Leave a reply



Submit