IT Consultant – Java, J2EE, IBM WebSphere Portal, Lotus Notes/Domino
RSS icon Home icon
  • Sun JDK5/6 compilers broken when linking overloaded methods with variable arguments

    (5 votes) 1 Star2 Stars3 Stars4 Stars5 Stars
    Loading...
    Posted on 16 May 2008 Sebastian Thomschke*/?> 1 comment

    We are currently switching the build system of OVal from custom Ant scripts to Maven 2. During that process we accidentally compiled the project using the Java compiler of the Sun JDK 5 instead of the AspectJ compiler. Surprisingly javac did not complain about the missing aspect class files. Instead it already aborted while compiling an ordinary Java class which only referenced other non-AspectJ related classes. This is the original error message:

    [INFO] [compiler:compile]
    [INFO] Compiling 180 source files to C:\projects\oval\src\trunk\target\classes
    [INFO] ------------------------------------------------------------------------
    [ERROR] BUILD FAILURE
    [INFO] ------------------------------------------------------------------------
    [INFO] Compilation failure
    C:\projects\oval\src\trunk\src\main\java\net\sf\oval\Validator.java:[373,58] 
    addMethodParameterChecks(java.lang.reflect.Method,int,java.lang.Object)
    has private access in net.sf.oval.internal.ClassChecks 

    There exist multiple methods named addMethodParameterChecks in the class ClassChecks with different signatures. The problem is that javac tries to link against the wrong method when compiling the class calling one of the methods.

    Here is an example of two simple classes that reflect the constellation can be used to reproduced the problem:

    public class ClassWithVarArgs
    {
    	public void foo(String... strings)
    	{
    		for (String string : strings)
    		{
    			System.out.println("String:" + string);
    		}
    	}
    
    	private void foo(Object obj)
    	{
    		System.out.println("Object:" + obj);
    	}
    }
    public class OtherClass
    {
    	public OtherClass()
    	{
    		ClassWithVarArgs instance = new ClassWithVarArgs();
    		instance.foo("string");
    	}
    }

    Class ClassWithVarArgs declares two foo methods one having variable arguments of type String, the other one having a single parameter of type Object. The constructor of class OtherClass instantiates an object of type ClassWithVarArgs and then calls the foo method with a String object. The suitable foo method to link against would be public void foo(String… strings) since it has the right visibility and a matching signature allowing the caller to either pass in a single String object or an array of Strings.

    However if you try to compile these classes using javac it will fail with:

    src\OtherClass.java:6: foo(java.lang.Object) has private access in ClassWithVarArgs
                    instance.foo("string");
                            ^
    1 error

    javac tries to link against private void foo(Object obj) instead of public void foo(String… strings) which is obviously wrong. The dangerous thing is, if private void foo(Object obj) is declared public instead, then javac will successfully compile the classes but will link against the wrong method.

    I tried javac of JDK 1.5.0_15 and 1.6.0_05 both show the same behavior.

    To see how Eclipse interprets this constellation I opened the Java files in Eclipse, navigated the cursor to the instance.foo(“string”); method and pressed F3 to open the declaration. Eclipse correctly jumped to the method declaration with the variable arguments.

    I did not test other JDK implementations. Currently I only know that AspectJ’s compiler does it right.

     

    1 responses to “Sun JDK5/6 compilers broken when linking overloaded methods with variable arguments” RSS icon

    Leave a reply