This was originally an issue report (hence the format of this mail), but I
finally decided to turn it into a discussion here.
*Found in GWT Release (e.g. 1.5.3, 1.6 RC):*
trunk at r9715
*Encountered on OS / Browser (e.g. WinXP, IE6-7, FF3):*
N/A (compile time; I haven't tried in DevMode)
*Detailed description (please be as specific as possible):*
I have a class A (it's actually an EntityProxy, but that's not the problem
here) with a List<Foo> property, and an AEditor implements Editor<A> that
should display the list.
Foo extends a BaseFoo class that's used in other classes (e.g. class B has a
List<FooB> property, where FooB extends BaseFoo too), and the editors for
those classes all display BaseFoo subclasses the same way.
So, I create a BaseFooEditor implements Editor<BaseFoo>, and in the AEditor
I use a ListEditor<BaseFoo, BaseFooEditor> (I cannot use a ListEditor<Foo,
BaseFooEditor> because ListEditor is declared as <T, E extends Editor<T>>,
and not <T, E extends Editor<? super T>>).
When compiling the app, I get the following error:
[INFO] Scanning for additional dependencies: .../AEditor.java
[INFO] Adding '75' new generated units
[INFO] Validating newly compiled units
[INFO] [ERROR] Errors in '...\AEditor_foos_Context.java'
[INFO] [ERROR] Line 17: Type mismatch: cannot convert from
List<Foo> to List<BaseFoo>
That "Line 17" is the body of the getFromModel method:
@Override public java.util.List<xxx.BaseFoo> getFromModel() {
return (parent != null && true) ? parent.getFoos() : null;
}
To make it work, getFromModel's return type would have to be List<? extends
xxx.BaseFoo>, i.e. the class should be declared as extending
AbstractEditorContext<List<? extends xxx.BaseFoo>> instead of
AbstractEditorContext<List<xxx.BaseFoo>>.
This means ListEditor would have to be defined as CompositeEditor<List<?
extends T>, T, E> instead of CompositeEditor<List<T>, T, E>. That would make
it possible to edit a List<Foo> with a ListEditor<BaseFoo, BaseFooEditor>,
just like you could edit a Foo with a BaseFooEditor, but that would be a
breaking change (see the first patch set in
http://gwt-code-reviews.appspot.com/1357803/show).
So instead, I propose that ListEditor be declared as ListEditor<T, E extends
Editor<? super T>> instead of ListEditor<T, E extends Editor<T>> (and same
for CompositeEditor and OptionalFieldEditor), as in the second patch set in
http://gwt-code-reviews.appspot.com/1357803/show (notice that it doesn't
require any change in unit tests, which makes me believe it's not a breaking
change).
Note that the exact same code worked in 2.1.1 (because the EditorDelegate
was created with the raw java.util.List type).
I understand however that it was a mistake to use a ListEditor<BaseFoo,…>
when the edited list is a List<Foo> (the problem here is actually how
generics are implemented in Java), but then the only solution would be to
parameterize my BaseFooEditor with <T extends BaseFoo> and then use a
ListEditor<Foo, BaseFooEditor<Foo>>, but I believe it shouldn't be
necessary.
*Shortest code snippet which demonstrates issue (please indicate where
actual result differs from expected result):*
abstract class BaseFoo { ... }
class Foo extends BaseFoo { ... }
class A {
private List<Foo> foos;
public List<Foo> getFoos() { return foos; }
public void setFoos(List<Foo> foos) { this.foos = foos; }
}
class BaseFooEditor implements Editor<BaseFoo> { ... }
class AEditor implements Editor<A> {
// cannot use ListEditor<Foo, BaseFooEditor> because ListEditor
// is declared as ListEditor<T, E extends Editor<T>> and not
// ListEditor<T, E extends Editor<? super T>>
ListEditor<BaseFoo, BaseFooEditor> foos;
}
*Workaround if you have one:*
Make BaseFooEditor a parameterized class:
class BaseFooEditor<T extends BaseFoo> implements Editor<T> { ... }
so you can declare the editor as ListEditor<Foo, BaseFooEditor<Foo>>
Note that in our case, we don't use ListEditor directly, we instead have a
widget that implements IsEditor<ListEditor<BaseFoo, BaseFooEditor>>. And
actually, that widget doesn't implement IsEditor directly, but extends
another widget (AbstractListWithSomeBehaviorEditor<T, E extends Editor<T>>)
which itself extends another widget (AbstractListEditor<T, E extends
Editor<T>, ...some other parameterization...>) which is the one that
implements IsEditor<ListEditor<T, E>>!
And the BaseFooEditor is used elsewhere to edit single-valued properties
(not to mention that we also have the issue with a BaseBarEditor,
BaseBazEditor, BaseQuuxEditor, etc.)
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors