|
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 :
customer 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 ----------
Posted Date : 2005-12-19 20:58:57.0
|
|
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.
Posted Date : 2008-02-22 18:42:37.0
|