JDK-6365166 : javac (generic) unable to resolve methods
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 5.0
  • Priority: P5
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2005-12-19
  • Updated: 2011-05-18
  • Resolved: 2011-05-18
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 7
7 b27Fixed
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.5.0_05"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_05-b05)
Java HotSpot(TM) Client VM (build 1.5.0_05-b05, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
javac failes to resolve the generic invocation for the methods as detailed in the code segments

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
compile the code supplied

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
code should compile and run
ACTUAL -
erro produced from javac


ERROR MESSAGES/STACK TRACES THAT OCCUR :

 <L,LF>addOrCreate4(java.lang.Number,L,LF) in NewTest<java.lang.Long,java.lang.Number> cannot be applied to (int,java.util.List<java.lang.Number>,NewTest.ListFactory<java.lang.Number>)


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.util.*;

public class NewTest<A,B> {
    private List<A> toAdd;
    
    public NewTest(List<A> toAdd) {
        this.toAdd = toAdd;
    }
    
    private List<A> getRelated(B b) {
        //some application logic
        //for demo
        return toAdd;
    }
    
    @SuppressWarnings("unchecked")
    public <L extends List<? super A>,LF extends Factory<L>> L addOrCreate4(B b,L l,LF lf) {
        if (l == null) {
            l = lf.create();
        }
        ((List<? super A>)l).addAll(getRelated(b)); //to get round the compiler bug
        return l;
    }
    
    public static class ListFactory<T>  implements Factory<List<T>>{
        public List<T> create() {
            return new ArrayList<T>();
        }
    }
    public static interface Factory<T> {
        public T create();
    }
    
    public static void main(String ... args) {
        ListFactory<Number> lf = new ListFactory<Number>();
        List<Long> longs = new ArrayList<Long>();
        longs.add(new Long(1));
        NewTest<Long,Number> test = new NewTest<Long,Number>(longs);
        
        List<Number> ret4 = null;
        
        ret4 = test.addOrCreate4(1, ret4,lf);
        
    }
}

---------- END SOURCE ----------

Comments
SUGGESTED FIX The problem described in this CR has been solved by CR 6356673
02-04-2008

EVALUATION This is a capture conversion bug. In particular, during the method call "l.addAll(la)" we have the following situation: -the type of the receiver is List<? super A> after capture conversion. This yields the type List<#CAP1>, where the lower bound of #CAP1 is A, while the upper bound of #CAP1 is Object. -the formal signature of addAll() is addAll(Collection<? extends E>), where E is a type variable of the class Collection<E>. -the type of the actual argument la is the type of la List<A>. After having having applied 15.12.2.2 (Applicable method by subtyping) we have that both List.addAll(), Collection.addAll(), ... So the compiler should apply JLS 15.12.2.5 (Choosing the most specific method). This process consists in finding which of the previously found methods is the most appropriate for the call. This is done by basically ensuring that the formals arguments of the most specific method are subtypes of the formals of the other method. In this case we have: m1 = List<#CAP1>.addAll(Collection<? extends #CAP1>) m2 = Collection<#CAP1>.addAll(Collection<? extends #CAP1>) So the subtyping test for the only argument of addAll() can be written as follows: Collection<? extends #CAP1> <: Collection<? extends #CAP1> Those types seems quite similar but the compiler won't treat them as such. Instead javac goes on and capture the LHS thus causing the subtyping test to fail.
19-02-2008