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

Reply via email to