<errorMessage>
Rewriting\src\java\gov\sc\eip\report\birt\ChangesRowGenerator.java:116:
reference to addAll is ambiguous, both method
addAll(java.util.Collection<? extends E>) in
java.util.Collection<capture#420 of ? super
gov.sc.eip.report.birt.items.ChangeRow> and method
addAll(java.util.Collection<? extends E>) in java.util.List<capture#420 of
? super gov.sc.eip.report.birt.items.ChangeRow> match
</errorMessage>
I didn't post an SSCCE because (1) I'm not sure I'm allowed to and (2)
because I think the error message is sufficient to demonstrate that there
may be a bug... either in the compiler, or in my understanding of
overwriting.
It seems to me that the error message is saying that it cannot determine,
from my code, whether the .addAll() which I am calling refers to the
.addAll in java.util.Collection or the .addAll() in java.util.List. But
doesn't the .addAll() in java.util.List overwrite the .addAll() in
java.utilCollection, so that the "List-version" always be the one invoked?
And anyway, aren't these both interfaces, and thus provide zero
implementation, and thus it doesn't really matter which of these two
methods are being called, since they will eventually point to the exact
same implementation depending on what underlying concrete type is
involved?
In case it's relevant, I'll include the statement where the error is
generated:
<veryShortSnippet>
rows.addAll(getRowForGenericChange(changeSet.getCountyChange(),
CommonFieldNamesEnum.COUNTY.getCode()));
</veryShortSnippet>
"rows" is a parameter past into the method of type "List<? super
ChangeRow>". As you can see, I'm not doing any weird casting to bypass the
overwriting (e.g. I'm not doing something like
"((Collection)rows).addAll(whatever)", which in my opinion should work
even if I did do that anyway).
- Oliver
I assume E extends ChangeRow.
> And anyway, aren't these both interfaces, and thus provide zero
> implementation, and thus it doesn't really matter which of these two
> methods are being called, since they will eventually point to the exact
> same implementation depending on what underlying concrete type is
> involved?
It doesn't matter if the (non-private, non-static) method is being
called is defined in an interface or a class (other than the instruction
is invokeinterface vs invokevirtul).
> <veryShortSnippet>
> rows.addAll(getRowForGenericChange(changeSet.getCountyChange(),
> CommonFieldNamesEnum.COUNTY.getCode()));
> </veryShortSnippet>
That rules out the only tenuous explanation I could think of (that it
was something wacky to do with inner classes).
> "rows" is a parameter past into the method of type "List<? super
> ChangeRow>". As you can see, I'm not doing any weird casting to bypass the
> overwriting (e.g. I'm not doing something like
> "((Collection)rows).addAll(whatever)", which in my opinion should work
> even if I did do that anyway).
The obvious work around is to assign rows to a Collection<? super
ChangeRow> variable. (I assume ChangeRow has no generic parameters.)
Tom Hawtin
There is no actual "E" in my code. I think the "E" comes from Sun's
implementation onf java.util.List.class and java.util.collection.class.
The variable "rows" involed here is declared as "List<? super ChangeRow>
rows", so I guess "E" is "? super ChangeRow" and so the method addAll's
generic type is "? extends (? super ChangeRow)" (not sure if that even
makes sense). But anyway, I think, from a language-specification point of
view, the error doesn't really have anything to do with generics.
However, from a practical-implementation point of view, if this is indeed
a bug in the compiler and not in my understanding, I can imagine how
throwing generics in the mix might have introduced this bug.
>
>> And anyway, aren't these both interfaces, and thus provide zero
>> implementation, and thus it doesn't really matter which of these two
>> methods are being called, since they will eventually point to the exact
>> same implementation depending on what underlying concrete type is
>> involved?
>
> It doesn't matter if the (non-private, non-static) method is being
> called is defined in an interface or a class (other than the instruction
> is invokeinterface vs invokevirtul).
Right, but what I meant is that we have a class hierarchy like:
public interface Collection<E> {
public void addAll(Collection<? extends E> stuffToAdd);
}
public interface List<E> extends Collection {
public void addAll(Collection<? extends E> stuffToAdd);
}
public class ArrayList<E> implements List<E> {
/* etc. */
}
so that when you have code like:
public void myMethod(List<? super ChangeRow> rows) {
rows.addAll(getSomeData());
}
public List<? super ChangeRow> getSomeData() {
List<ChangeRow> returnValue = new ArrayList<ChangeRow>();
return returnValue;
}
there should be no reason to ask whether the .addAll() refers to the one
in Collection, or the one in List. I've got a
multiple-interface-inheritance situation, and *not* a
multiple-implementation-inheritance situation; thus the "diamond problem"
does not come up, and thus there should be no ambiguity about which method
I'm invoking when I call .addAll().
>
>> <veryShortSnippet>
>> rows.addAll(getRowForGenericChange(changeSet.getCountyChange(),
>> CommonFieldNamesEnum.COUNTY.getCode()));
>> </veryShortSnippet>
>
> That rules out the only tenuous explanation I could think of (that it
> was something wacky to do with inner classes).
Right, the code is structurally very straightforward (it's essentially
a CRUD web app). No inner classes anywhere to be seen.
>
>> "rows" is a parameter past into the method of type "List<? super
>> ChangeRow>". As you can see, I'm not doing any weird casting to bypass
>> the overwriting (e.g. I'm not doing something like
>> "((Collection)rows).addAll(whatever)", which in my opinion should work
>> even if I did do that anyway).
>
> The obvious work around is to assign rows to a Collection<? super
> ChangeRow> variable. (I assume ChangeRow has no generic parameters.)
I'll give that a try and ask my coworker to compile again and see what
happens.
- Oliver
At this point, I'm relatively confident it's a compiler bug. I can't
reproduce the error using 1.5.0_06-b05, 1.6.0-b105, 1.6.0_01-b06 nor
1.6.0_02-b06. My coworker's version is 1.6.0_02-b05 which I can't seem to
find online.
- Oliver
Could it be this?:
<http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6356673>
That's for a 1.5 version, but note the comments and one of the related
bugs. It's been present in all the 1.6 versions I've tried.
As it's a List, perhaps you could try using addAll(int, ...) as a
workaround.
--
ss at comp dot lancs dot ac dot uk |
>Rewriting\src\java\gov\sc\eip\report\birt\ChangesRowGenerator.java:116:
>reference to addAll is ambiguous, both method
>addAll(java.util.Collection<? extends E>) in
>java.util.Collection<capture#420 of ? super
>gov.sc.eip.report.birt.items.ChangeRow> and method
>addAll(java.util.Collection<? extends E>) in java.util.List<capture#420 of
>? super gov.sc.eip.report.birt.items.ChangeRow> match
></errorMessage>
This sort of problem happens when you use java.util.List and
java.awt.List in the same program. You have to fully qualify each
reference with package name to avoid ambiguity.
However, your case is more peculiar.
It looks as if are doing x.addall(
where x is both a Collection and a List.
Yet this should not cause trouble. List is a subinterface of
Collection.
The practical way out of this is to define x concretely, e.g.
ArrayList<Thing> x = new ArrayList<Thing>( 2000);
x.addAll (myThingCollection);
Please post code, at least your imports, where you define x, where
you define the collection and the type of the collection and the
addall. This is intriguing.
--
Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com
It looks very similar to my issue, except that I think my situation is
much simpler than the part which goes "<L extends List<? super A>>";
instead, it's simply "List<? super ActualClassNotATypeVariable>"
>
> As it's a List, perhaps you could try using addAll(int, ...) as a
> workaround.
I couldn't get the bug to reproduce on my machine, so I advised my
coworker to try updating to a newer version of Java. He hasn't told me
whether or not that made the problem go away. If it's still present, your
solution sounds like the least messy one so far.
- Oliver
Right, there's no reference to java.awt.* at all: It's a web
application, not a desktop one.
>
> It looks as if are doing x.addall(
>
> where x is both a Collection and a List.
>
> Yet this should not cause trouble. List is a subinterface of
> Collection.
Agreed.
>
> The practical way out of this is to define x concretely, e.g.
>
> ArrayList<Thing> x = new ArrayList<Thing>( 2000);
> x.addAll (myThingCollection);
>
> Please post code, at least your imports, where you define x, where
> you define the collection and the type of the collection and the
> addall. This is intriguing.
We (the company I work for) actually don't fully own the code. It's
shared among a couple of developers working for several different
companies all collaborating on one big project, so I'm not sure I can post
the full code. Furthermore, since I can't actually replicate the problem
on my machine, I can't really compose an SSCCE, because I can't test
whether the parts which I consider "unimportant" actually affect the bug
or not: No matter what I add or remove, the code compiles fine on *my*
machine.
- Oliver
Note the GenericCaptureAddingTest example further down, which I think is
more similar (although it's for Set, but I get the same problem when I
change it to List).
While Java 7 proposed features remains a hot topic, let's propose
making this legal:
import java.util.List;
import java.awt.List AList;
...
List x = new LinkedList(); // a java.util.List
AList y = new AList(); // a java.awt.List
It just means adding an alternate legal form of import statement,
without losing backward source compatibility:
import fully-qualified-class alias;
and the stock import is then essentially just an elliptical form that
defaults "alias" to the last chunk of the fq class name.
>While Java 7 proposed features remains a hot topic, let's propose
>making this legal:
>
>import java.util.List;
>import java.awt.List AList;
that is reminiscent of the way Eiffel lets you get around the problem
of duplicate names with multiple inheritance.
Yes, but multiple inheritance is evil, and this is closer to some C++
"using" and "typedef" usages and won't introduce any real cruftiness.
Well, unless someone goes out of their way with gratuitously aliasing
common standard library classes in e.g. java.util or java.io to wacky
names just to be a pain or maybe in the vain hope of job security
through indispensibility if the code is ever to be maintained; but
that's always going to be possible, whether by hairy use of imports,
hairy entangled masses of nested and anonymous inner classes, or just
hairy entangled messes of for and while loops full of break and
continue statements to recreate the bad old days of GOTO-ridden ROM-
BASIC-inspired spaghetti code.
Mind you they should get extra bonus points* for confusingly aliasing
classes in java.lang, especially String and the basic exception
classes, and referring to each under both the usual name AND the alias
and picking which to use at each site in a random fashion.
* Each bonus point redeemable for one (1) free pink slip of course.
I think, that's the same bug.
Just for fun, I've slightly modified that example to reflect as close as
possible the Oliver's situation, here is the SSCCE:
import java.util.List;
public abstract class Test {
public interface ChangeRow {}
public void addData(List<? super ChangeRow> rows) {
rows.addAll(getSomeData());
}
protected abstract List<? extends ChangeRow> getSomeData();
}
On my machine (Windows XP, Intel 32bit), compiling the above example
produce the following output:
Test.java:8: reference to addAll is ambiguous, both method
addAll(java.util.Collection<? extends E>) in
java.util.Collection<capture#156 of ? super Test.ChangeRow> and method
addAll(java.util.Collection<? extends E>) in java.util.List<capture#156
of ? super Test.ChangeRow> match
rows.addAll(getSomeData());
^
1 error
This bug is reproducible using 1.6.0-beta2-b86, 1.6.0-b105, and
1.6.0_02-b06. Example compiles successfully with 1.5.0_04-b05,
1.5.0_06-b05, and 1.6.0-beta2-b73. (I have no other Java 5+ VMs
installed to test it)
piotr
Bingo, you've found it. I tried your example, and it compiles fine
with:
javac 1.5.0_06
But triggers the bug in:
javac 1.6.0
javac 1.6.0_01
javac 1.6.0_02
- Oliver
FYI, I submitted a new bug report to Sun on this just before this thread
started, and they've got back to me to say it has been fixed in JDK7,
and will also be fixed in a future JDK6 update.
I don't know about you, but personally, I find "a future JDK6 update"
to be somewhat vague and unhelpful ...