Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@SafeVarargs on interface method

In this code,

package com.example;

interface CollectorIF<T> {
    // @SafeVarargs         // Error: @SafeVarargs annotation cannot be applied to non-final instance method addAll
    void addAll(T... values);   
}

class Collector<T> implements CollectorIF<T> {

    @SafeVarargs
    public final void addAll(T... values) {
    }
}

class Component<T> {

    public void compute(T value) {
        Collector<T> col1 = new Collector<>();
        col1.addAll(value);   // No warning

        CollectorIF<T> col2 = new Collector<>();
        col2.addAll(value);   // Type safety: A generic array of T is created for a varargs parameter
    }
}

the Type safety: A generic array of T is created for a varargs parameter warning does not occur when using a Collector<T> reference, due to the @SafeVarargs annotation.

However, the warning does occur when accessing the method through the CollectorIF<T> interface. On interface methods, @SafeVarargs is not valid (which is obvious since the compiler can not perform any checks on the usage of the parameter in the method body).

How can the warning be avoided when accessing the method through an interface?

like image 990
Andreas Fester Avatar asked Jun 15 '16 07:06

Andreas Fester


People also ask

What is @SafeVarargs annotation in Java?

It is an annotation which applies on a method or constructor that takes varargs parameters. It is used to ensure that the method does not perform unsafe operations on its varargs parameters. It was included in Java7 and can only be applied on. Final methods.

What is the use of SafeVarargs in Java?

Annotation Type SafeVarargsA programmer assertion that the body of the annotated method or constructor does not perform potentially unsafe operations on its varargs parameter.


1 Answers

There's no way to avoid this warning, because there's no way to safely define an interface that has a generic varargs method.

Another implementation of CollectiorIF could misuse the parameter, rendering any caller of CollectorIF.addAll() vulnerable to strange runtime behavior. You could make a case that interfaces and non-final methods should allow @SafeVarargs (and require that implementing/overriding methods be similarly annotated), but presently the Java devs made a conscious decision not to support that pattern.

The JLS provides a little more background:

The annotation is not usable where method overriding occurs. Annotation inheritance only works on classes (not methods, interfaces, or constructors), so an @SafeVarargs-style annotation cannot be passed through instance methods in classes or through interfaces.

~JLS §9.6.4.7

In the meantime you have two choices; ignore the warning or refactor your API.

Refactoring your API is actually likely to be exactly what you want, since generic vararg methods should only be used as bridges to the real, properly-generic implementation. Instead of defining it as part of your interface (and therefore requiring all implementations implement it) provide it as a static utility method, thereby making the interface's API smaller while still giving callers the flexibility to use varargs. As of Java 8 the utility method can even be defined in the interface.

@SafeVarargs
public static <T> void addAll(CollectorIF<T> collector, T... values) {
  collector.addAll(Arrays.asList(values));
}

Your interface should then define a addAll(Iterable<T> values) method which lets implementors avoid the crufty world of generic varargs entirely.

like image 140
dimo414 Avatar answered Sep 20 '22 15:09

dimo414