JDK-8075323 : Unable to invoke bridge for vararg method
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 7,8,9
  • Priority: P2
  • Status: Resolved
  • Resolution: Not an Issue
  • OS: generic
  • CPU: x86
  • Submitted: 2015-01-13
  • Updated: 2018-11-19
  • Resolved: 2016-03-03
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.
JDK 9
9Resolved
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b18)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.3.9600]

A DESCRIPTION OF THE PROBLEM :
If a class overrides a method with varargs then jdi is unable to invoke such method, see source sample.
We look for 
foo(Object a, Object... args)
as it is declared in Base class.
concreteMethodByName returns the bridge method in Child class,
but it is not marked as vararg in class file.
And invocation of such method with one parameter produce:
java.lang.IllegalArgumentException : Invalid argument count: expected 2, received 1
If we invoke the "real" method foo(String a, String... args) everything works fine.

I'm not sure if it is the compiler that should mark such bridge as vararg or jdi should handle this.

This affects evaluation in IDEs (Netbeans, IDEA),
see https://youtrack.jetbrains.com/issue/IDEA-129869 for example.


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class Varargs {

    public static void main(String[] args) {
        Base b = new Child();
        b.foo("dd"); // stop here and try to evaluate b.foo("dd")
    }

    public static class Base<T> {
        CharSequence foo(T a, T... args) {
            return a.toString();
        }
    }

    public static class Child extends Base<String> {
        String foo(String a, String... args) {
            return a.toString();
        }
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
In the provided test sample you can evaluate  ((Child)b).foo("dd");


Comments
Please forget the sample program, no need to fix it. Bridge method for a method with ACC_VARARGS does not have ACC_VARARGS. Is that by design or a bug?
19-11-2018

This program is not type safe and deserves what it gets: See the code generated for main and in particular the line annotated with "HERE" public static void main(String[] args) { Base b = new Child(); b.foo("dd"); // stop here and try to evaluate b.foo("dd") } public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=2, args_size=1 0: new #2 // class X$Child 3: dup 4: invokespecial #3 // Method X$Child."<init>":()V 7: astore_1 8: aload_1 9: ldc #4 // String dd 11: iconst_0 12: anewarray #5 // class java/lang/Object // <<------------------------------ HERE 15: invokevirtual #6 // Method X$Base.foo:(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/CharSequence; 18: pop 19: return At the call site the varargs are packed into an Object array. This cannot be cast to a String [] required by the runtime instance. A singleton String object can be assigned to an Object, passed to another object and then safely cast back to the String. An array of Strings cannot be packed into an Object array, passed to another Object array and then cast back to a String [] (while the individual cells can be cast to String) The best that compilers can do here is to warn about type safety - which javac does. There is nothing more that can be done. Solution is to eliminate the type unsafetyness in the program. E.g avoid raw type usage by changing the statement Base b = new Child(); to Base<String> b = new Child();
03-03-2016

This is not a compiler defect. The use of raw types at the call site forces the compiler to use Object [] as that is the type seen by the compiler for the varargs parameter.
03-03-2016

java.lang.String foo(java.lang.Object, java.lang.Object[]); descriptor: (Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/String; flags: ACC_BRIDGE, ACC_SYNTHETIC Code: stack=3, locals=3, args_size=3 0: aload_0 1: aload_1 2: checkcast #3 // class java/lang/String 5: aload_2 6: checkcast #4 // class "[Ljava/lang/String;" 9: invokevirtual #5 // Method foo:(Ljava/lang/String;[Ljava/lang/String;)Ljava/lang/String; 12: areturn _checkcast S java.lang.String T java.lang.String _checkcast S [Ljava.lang.Object; T [Ljava.lang.String; CCE S_objName [Ljava.lang.Object; T_klassName [Ljava.lang.String; Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String; at TestMe$SChild.foo(TestMe.java:16) at TestMe.main(TestMe.java:39)
29-01-2016

Classcast exceptions happens if you attempt to run attached testcase with no debugger connected.
28-01-2016

This is an issue existance of String foo(String a, String... args) method in the child class creates the issue and not able to mark the bridge methods. If we comment the String foo(String a, String... args) method in child or typecast the base object to ((Child)b).foo("dd") code works fine. Exception - Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String; at Varargs$Child.foo(Varargs.java:14) at Varargs.main(Varargs.java:5) Issue observed in all the versions of 7, 8 and 9 7uxx - Fail 8uxx - Fail (Including 8u72) 9 ea b-96 - Fail
24-12-2015