Warning for common varargs

I declared the following method:

private void mockInvokeDBHandler(Map<String, Object>... rows) { List<Map<String, Object>> allRows = Arrays.asList(rows)); // rest of method omitted } 

It is called by clients using something like

 Map<String, Object> row1 = new HashMap<String, Object>(); Map<String, Object> row2 = new HashMap<String, Object>(); mockInvokeDBHandler(row1, row2); 

However, the last line shown above generates a warning

Security Type: creates a general Map array for the varargs parameter

I don’t quite understand this, but I think this is because the varargs parameters are converted to arrays, and it is a bad idea to have an array whose type is a common class (since generics are invariant and arrays are not).

I could solve this problem by reworking the method as

 private void mockInvokeDBHandler(List<Map<String, Object>> rows) { } 

But this puts the burden of putting string objects in a list on the client, which I would rather avoid. Is there a better solution?

+7
java generics variadic-functions
source share
4 answers

To pass arguments to the varargs method, the compiler will put the arguments into an array.

The warning should tell you that the compiler cannot guarantee that each of the elements of the array — each of the arguments to the varags method — is really Map<String, Object> .

This is a bit annoying warning because you cannot get around this except overriding the method signature so you don't use varargs. IMO is safe to ignore if you are sure of the actual runtime types of these arguments (which you are in this case).

+12
source share

This warning cannot be avoided except by adding @SuppresWarning("unchecked") to the method :)

Since you say that this is a private method, there are no “clients” in this case, and you control the method, so ignoring the warning seems reasonable.

Several times, when I created methods with parameterized types as the varargs parameter, I created several overloads:

 void mockInvokeDBHandler(Map<String, Object> map1) void mockInvokeDBHandler(Map<String, Object> map1, Map<String, Object> map2) void mockInvokeDBHandler(Map<String, Object> map1, Map<String, Object> map2, Map<String, Object>... othermaps) 

This can avoid some warnings, depending on the number of arguments.

+4
source share

You can reduce the burden of using a list instead of varargs with some builder interface (like the one I'm using ). Using this CollectionBuilder, it will become something like this:

 mockInvokeDBHandler(CollectionBuilder.<Map<String, Object>>list().add(map1).add(map2).get()); 

he is prettier without general arguments:

 import static at.molindo.utils.collections.CollectionBuilder.list List<String> list = list(String.class).add("foo").addAll(set).get(); 

This is definitely longer than the varargs solution, but in any case very convenient.

+2
source share

For those who land here, the answers are a bit old. Java 7 introduced the @Safevarargs annotation to solve this problem:

 @SafeVarargs private void mockInvokeDBHandler(Map<String, Object>... rows) { 

From javadoc:

The statement of the programmer that the body of the annotated method or constructor does not perform potentially dangerous operations on its varargs. Applying this annotation to a method or constructor suppresses unverified warnings about the unrecoverable type of the arity variable (vararg) and suppresses unverified warnings about creating a parameterized array when invoking sites.

+2
source share

All Articles