JDK-8060487 : Varargs array type incompatible with bridge method
  • Type: Bug
  • Component: specification
  • Sub-Component: language
  • Affected Version: 6,7,8,9
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2014-10-14
  • Updated: 2015-12-17
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbd_majorUnresolved
Related Reports
Relates :  
Description
If this test case is compiled with javac:

interface Iface<T extends Number> {
    String m(T...t);
}

public class Test {
    public static void main(String[] args) {
        Iface<? super Integer> i = (Integer...a) -> "";
        String result = i.m(1);
    }
}

at execution time you will get:

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Number; cannot be cast to [Ljava.lang.Integer;
at Test$$Lambda$1/980546781.m(Unknown Source)
at Test.main(Test.java:8) 

This is correct according to the current spec. It should be checked if the spec can be modified to deal better with similar cases.
Comments
This is a general problem, not something specific to lambdas or wildcards. The key ingredients: generic varargs, generic specialization. Here's another example: public class VarargsErased { interface Iface<T> { void m(T[] t); T get(); } static class IfaceString implements Iface<String> { public void m(String[] args) {} public String get() { return "a"; } } @SafeVarargs static <T> void callM(Iface<T> i, T... args) { i.m(args); } // extra layer to infer capture variables static <T> void test(Iface<T> i) { callM(i, i.get()); } public static void main(String... args) { Iface<String> i = new IfaceString(); //Iface<?> i = new IfaceString(); //Iface<? super String> i = new IfaceString(); //Iface i = new IfaceString(); test(i); } } In every case, we end up with a varargs array whose runtime type is a subtype of the invoked method parameter type (after erasure), but not a subtype of the overriding method parameter type (after erasure). Possible solutions: - This is just a limitation of the language. Sorry. (This makes things like variable-arity predicates effectively unusable with wildcards or type variables.) - Choose a better element type for the varargs array -- difficult or impossible in general, but maybe we can at least do better. (This is a behavioral change that could break existing corner-case programs.) - Expect bridge methods to allocate a new array and checkcast the elements. (Much more complex than existing bridge code, and has a cost linear in the array length.)
14-10-2014