PDA

View Full Version : Ext-GWT: stop the insanity



cletus
8 Jul 2008, 5:57 PM
Generics are a tool and like any tool they can be used well or abused and, after some extensive use of Ext-GWT, I'm sorry to say that this is (mostly) a

case of abused Generics. I'll highlight some of the reasons why.

Firstly however a note about the positive. The widgets themselves look great and theres a good selection (although, oddly, theres no Image Button;

why?). That is primarily what I want from a UI library. The API in a lot of ways is secondary and this is teh case here too. Secondary doesn't mean

its unimportant however.

I don't know the history of GWT-Ext other than it has its roots in MyGWT (which I liked) and ExtJS (which I've never used). The idea to use generics is

good but generics aren't simple. You only need to see a declaration like "<X> X max(Collection<? super X> collection)" to realize that and they need to

be used properly. For better or worse this takes a fair bit of knowhow. Its why the Java Generics FAQ is as large as it is and why it takes someone of

the calibre of Josh Bloch to explain it.

1. Model

Put simply: all models are Maps. Some might disagree with me but that is (imho) not a good thing. For instance, the ModelData interface has a method:

public <X> X get(String property);

This is obviously so you can do things like:

Date date = model.get("startDate")
int pageCount = model.get("pageCount") // auto-unboxing to boot

While this might be convenient in that you don't have to explicitly cast but because of type erasure, you're not actually gaining anything. This is

perfectly legal code:

model.put("date", "testing 123");
Date d = model.get('date");

The result is of course a ClassCastException. Josh Bloch, just to give one example, suggests the use of heteregenous containers eg:

container.put(String.class, "blah");

In Swing, models are basically just POJOs with relevant adapters like TableModel and frankly instead of:

model.get("dateOfBirth")
model.set("dependants", 2)

I prefer:

model.getDateOfBirth()
model.setDependants(2)

I realize some will disagree with this but remember that a strongly typed model like this doesn't preclude the use of Maps whereas the use of Maps makes

strongly typed accessors and mutators little more than syntactic placebos. Granted also that GWT doesn't have access to reflection, which is potentially

limiting.

2. Model Events

BaseModel doesn't fire a lot of events. Basically the only one is Events.Update. Even removing a property fires an Update event where the new value is

null, which--from an event perspective--is indistinguishable from actually setting the property to null (even though the latter leaves the property in

the map and the former does not). This is a problem.

Shouldn't adding a new property trigger an Add event and rmeoving an existing property trigger a Remove event?

This particular code highlights some issues that are worth pointing out as examples of suboptimal Java code:

From BaseModelData:

public void setProperties(Map<String, Object> properties) {
for (String property : properties.keySet()) {
set(property, properties.get(property));
}
}

should be:

public void setProperties(Map<String, Object> properties) {
for (Map.Entry<String, Object> entry : properties.entrySet()) {
set(entry.getKey(), entry.getValue());
}
}

and this:

protected <X> X getNestedValue(ModelData model, List<String> paths) {
if (paths.size() == 1) {
return (X) model.get(paths.get(0));
} else {
Object obj = model.get(paths.get(0));
if (obj != null && obj instanceof ModelData) {
ArrayList<String> tmp = new ArrayList<String>(paths);
tmp.remove(0);
return (X) getNestedValue((ModelData) obj, tmp);
}
}
return null;
}

has two faults:

1. The cast to X on line 3 highlights the issue described earlier regarding get() (ie unchecked cast); and

2. Line 6 can be simplified to:

if (obj instanceof ModelData) {

If obj is null then that returns false.

3. Nested Properties

For those unfamiliar with it, the BaseModel implementation has a feature called nested properties. Basically if you do this:

BaseModel a = new BaseModel();
BaseModel b = new BaseModel();
a.set("count", 3);
b.set("blah", a);

then you can do this:

b.set("blah.count", 5);

Interestingly, this will potentially trigger TWO Update events: one on "blah.count" in b and one on "count" in a.

4. Model Collections

Models are flat except, as noted above, for nested properties. While this is potentially useful it needs to go further. Specifically I'm talking about

property values that are collections (namely lists). I've tried various ways of implementing some kind of ListModel but all the implementations are

pretty ugly because the Model interface is so geared towards Maps. A Model implementation isn't exactly what you want either because then it can

potentially have its own event listeners. If its not a Model a caller could get access to the List and modify it without triggering any events.

BaseTreeModel sort of does this but its also limited in that theres only one type of child (more on trees below).

Collection properties are a fairly compelling and common requirement (eg for items in a combo box) so I think this is something really lacking. About

the cleanest way to handle this would be to use an observer approach. Ignoring nested properties for simplicity, that would mean something like:

public class BaseModel ... {
class ModelList<T> extends AbstractList<T> {
private final List<T> delegate;

private ModelList(List<T> delegate) {
if (delegate == null) {
throw new NullPointerException("delegate is null");
}
this.delegate = delegate;
}

public int size() {
return delegate.size();
}

public T get(int index) {
return delegate.get(index);
}

public T set(int index, T element) {
// Update event at index
return delegate.set(index, element);
}

public void add(int index, T element) {
// fire Add event at index
delegate.add(index, element);
}

public T remove(int index) {
// fire Remove event at index
return delegate.remove(index);
}
}
}

Note: the above is just a rough guide.

Various methods in BaseModel and BaseModelData would need to be modified to handle collection properties.

Additionally, nested properties should support syntax like:

set("names[3]", "John Smith");

5. Tree Model

I've posted on this previously but for completeness I'll mention it here too. Basically the TreeModel interface is a good example of the abuse of

generics and bad design. Why? Because, TreeModel is an invasive interface. It forces every item in your tree model to implement TreeModel and leads to

silly declarations like this:

BaseTreeModel<BaseTreeModel> ...

This needs a far cleaner interface. The basic concept of a container (which TreeModel is or at least should be) is that it can contain anything. Look

no further than the Java Collections API and you'll see things like:

List<T> ...

not

List<T extends ListItem> ...

A good solid example of trees and tree models can be found in the swing JTree class.

The naming isn't clear either. TreeModel is really a node, not the whole tree model. A rough starting poitn for a good TreeModel interface would be:

interface TreeNode<T> {
TreeNode<? extends T> getParent();
List<TreeNode<? extends T>> getChildren();
T getValue();
TreeNode<T> insert(int index, T item);
T remove(int index);
void removeAll();
T setValue(T newValue);
}

The list of children should either be a defensive copy of the children or unmodifiable.

A TreeNode implementation like this will give you the ability to have async loads of children and so forth, something thats currently handled by a

confusing mix of loaders, binders and stores.

Oddly, TreeModel is generic in the current code but TreeItem isn't. If an internal UI-level tree is needed to mirror TreeNode (eg to contain styles and

ohter tree-implementation-specific state) it should be generic.

6. Events and Listeners

Events are an area desperately in need of review in Ext-GWT. The events themselves are integer constants when they should be an enum. You might argue

that this isn't extendible but thats not true. You simply have:

interface EventType {
String getName();
int getNumber();
}

enum BaseEvents implements EventType {
...
}

enum ExtendedEvents implements EventType {
...
}

and so on and then rather than the enums, the interface is used.

Events themselves are a concrete type with public fields. This should be an interface with a largely immutable implementation. For example:

interface Event {
EventType getEventType();
Object getSource();
}

Also, the generic Listener interface is just painful. addListener() says nothing about what events the model or widget is firing. This is perfectly valid:

textField.addListener(Events.BeforeAdd, new Listener ... )

Listener is generic but not in a useful way. This has led to code like:

tabPanel.addListener(Events.Remove, new Listener<ContainerEvent<TabPanel, TabItem>>() {
...
});

This is crazy. I'd much rather have correctly typed listeners and explicit add...Listener methods rather than addListener. For example:

public interface Model ... {
void addChangeListener(ChangeListener changeListener);
}

public interface ChangeListener {
void propertyChanged(PropertyChangeEvent event); // curently ChangeEvent is passed in and you need to cast it
}

7. Inconsistent Generics

Theres an awful lot of code that partially uses generics. For example, BaseTreeModel.adopt() has a parameter of type TreeModel, not TreeModel<something>. You'll find examples like this and assigning generic arguments to non-generic data members all over the place.

8. Conclusion

Theres some pretty scary stuff in here and I know I've only scratched the surface. The current release is 1.0rc2 and I really have to consider this a political 1.0 release. Its nowhere near ready for primetime. Once 1.0 is release this bizarre API is basically set in stone. Hell, its almost set in stone by the RC designation.

On the project I'm working on we were using MyGWT and quite liked it. It was a natural move to Ext-GWT but we're being forced to abandon it entirely as we learn more about it in favour of vanilla GWT. Sure we won't have ContentPanels that way but we won't have BaseTreeModel<BaseTreeModel> either. A non-generic interface is preferable to a badly designed and inconsistent generic interface and thats what Ext-GWT is.

sheesh-kebab
8 Jul 2008, 6:14 PM
disregarding some rants in the post, I agree with the points - I've also noticed some generics abuse. My guess is that some of the things happened due to attempts to approximate extjs javascript api using java, which is rather badly suited for the task. More explicitly defined setters, getters, addxxxListener type api, mimiking Swing would probably look a bit more readable to a java developer.

Payam
8 Jul 2008, 7:42 PM
I agree as well.
Sometimes, there was so much generics use, I was confused as hell.

Initially i thought, "wow that is a good way of using generics",
but then I realized I had no idea what was going on.

Please make it like Swing, its what Java developers are best with :)

craigday
8 Jul 2008, 7:52 PM
Wholeheartedly agree. I previously raised a query about the Tree design, which was promptly ignored. GXT in it's current form is a massive opportunity wasted. It's quite possibly the most painful library I have ever had to work with. Every day I say to my guys, "have we found an alternative to GXT yet?" The closed open-source model (no access to subversion, private forums - how sad) and the RC status of the current codebase gives me little hope that GXT can be saved.

Regards
Craig

Tereno
8 Jul 2008, 8:14 PM
No doubt the Tree design completely baffled me. And when I was looking at how Google implemented it, it just made so much more sense to do it that way. Why was the wheel reinvented for something that already works so well?

Apart from that, the rest is fairly easy to follow. Though I do wish there were more straightforward tutorials vs just samples of codes - the Tree source code did not help at all.

leonate
8 Jul 2008, 11:39 PM
I agree as well.
Although GXT widgets look good enough but what is under the hood sometimes scares me away from adopting the framework. :-?

zaccret
9 Jul 2008, 12:20 AM
Wow, this a is a really (too?) huge subject. I think you could have opened 7 threads instead of just one. Actually, some threads are already opened for some points. I give you the links.


public <X> X get(String property);

This is obviously so you can do things like:

Date date = model.get("startDate")
int pageCount = model.get("pageCount") // auto-unboxing to boot

While this might be convenient in that you don't have to explicitly cast but because of type erasure, you're not actually gaining anything. +1. Let's follow on existing thread : http://extjs.com/forum/showthread.php?t=40670


In Swing, models are basically just POJOs with relevant adapters like TableModel and frankly instead of:

model.get("dateOfBirth")
model.set("dependants", 2)

I prefer:

model.getDateOfBirth()
model.setDependants(2)

I realize some will disagree with this but remember that a strongly typed model like this doesn't preclude the use of Maps whereas the use of Maps makes strongly typed accessors and mutators little more than syntactic placebos. Granted also that GWT doesn't have access to reflection, which is potentially limitingI guess the lack of reflection is the reason we have these maps, but I also prefer strongly typed models. Here again, there are already other threads on that point but I'm glad you relaunch the discussion as this is an important point to me =D> Maybe follow the discussion on http://extjs.com/forum/showthread.php?t=38371


Even removing a property fires an Update event where the new value is null, which--from an event perspective--is indistinguishable from actually setting the property to null (even though the latter leaves the property in the map and the former does not). This is a problem.I have no real opinion about that, for now I have no need about this Update/Remove event


3. Nested Properties Also never used because I try to keep strongly typed models and I don't use the get/set methods (except for things like displayProperty).


4. Model Collections I think I don't understand what you say and don't see the interest (maybe because of my bad english level :"> or maybe because I don't use the get/set methods as I said above).


5. Tree Model Let's follow on existing thread : http://extjs.com/forum/showthread.php?t=40165


6. Events and Listeners Let's follow on existing thread : http://extjs.com/forum/showthread.php?t=38213



7. Inconsistent Generics

Theres an awful lot of code that partially uses generics. For example, BaseTreeModel.adopt() has a parameter of type TreeModel, not TreeModel<something>. You'll find examples like this and assigning generic arguments to non-generic data members all over the place.It would be nice to open a new thread for that point. About BaseTreeModel.adopt() method, it is a private method so we don't care about it, but like you I think there are some places where there are inconsistent use of generics (but not so numerous places).


8. Conclusion

Theres some pretty scary stuff in here and I know I've only scratched the surface. The current release is 1.0rc2 and I really have to consider this a political 1.0 release. Its nowhere near ready for primetime. Once 1.0 is release this bizarre API is basically set in stone. Hell, its almost set in stone by the RC designation.Mmm, I would say yes and no ;) It is true that some parts of code need (IMHO) to be refactored but the features are ready and that's what my team leader (and my customer) expect at first from the API, not the consistent use of generics :). Actually, I really don't think the API is set in stone. I have used the API for more than 2 months, and most of the times the community suggest enhancement on the API, Darell (the core developer) integrate it. I really believe it will follow this way.
By the way, when you say "I've only scratched the surface", you seem to believe there are a lot of other critical bad points in the API. I can say you that after 2 months of use, I haven't see other critical bad points, but I agree the API is enhanceable and I'll continue to contribute.


mimiking Swing would probably look a bit more readable to a java developer I also like Swing. Isn't GXT mimiking SWT/JFace (also a nice API, I think) ?

Grandiosa
9 Jul 2008, 3:49 AM
Thanks for taking the time to write up your thoughts on Ext-GWT architecture, there are many valid points.

I have a few comments.


...
Date date = model.get("startDate")
int pageCount = model.get("pageCount") // auto-unboxing to boot

While this might be convenient in that you don't have to explicitly cast but because of type erasure, you're not actually gaining anything. This is perfectly legal code:
In the context of "generics provide compile time type safety", you are absolutely correct, there is no gain. But still, since this construction makes a cast optional there is less noise in all the getters on your model object, for what it's worth...



In Swing, models are basically just POJOs with relevant adapters like TableModel and frankly instead of:

model.get("dateOfBirth")
model.set("dependants", 2)

I prefer:

model.getDateOfBirth()
model.setDependants(2)

Well who doesn't? But isn't the real question how to support POJO models in a databinding? As you said:


Granted also that GWT doesn't have access to reflection, which is potentially limiting.That's an understatement. ExtGWT has adopted a lightweight approach to provide introspection under the GWT JRE using Java Maps, and which has limitations like you point out.

Another and IMHO very elegant approach was taken by the Gwittir guys. They actually wrote a Java beans style Introspector for GWT, look here (http://code.google.com/p/gwittir/wiki/Introspection). In their solution model objects just have to implement a marker interface (Bindable), and all necessary introspection code to hook up your POJO getters/setters is generated during compile time.
Admittedly I haven't had time to testdrive their stuff, and they do point out that you should keep number of bindable objects to a minimal since their approach generates significant amounts of binding infrastructure code for your bound components.

Interestingly, while poking around trying to determine licensing and overall readiness of their library I noticed this (http://groups.google.com/group/gwittir-users/browse_thread/thread/134de4785c333328) post. I believe Cameron Braid is a ExtJS employee, or at least one of the architects behind the ExtGWT generics?


2. Model EventsI believe your comments concerning model events are just minor bugs, shouldn't be a problem to fix.


3. Nested PropertiesI am not 100% sure but I think you're not correct. Isn't cascading of update events from child to parent only applicable for children of a BaseTreeModel object (as in myTreeModel.add(new MyThreeModelChild) )



4. Model CollectionsExtGWT uses the Store approach for model collections required by combos and lists.

As for your proposal, it resembles the Gwittir approach mentioned earlier. In Gwittir you can bind to any child/field on your model class using standard object notation in the binding classifier.



5. Tree ModelI agree most of your comments.

Also there are, or at least was, issues with the GWT RPC/compiler when using plain BaseModel objects that return collection of other BaseModel objects. I ended up converting all my models to TreeModels to get around this, hence lots of model classes specifying themselves in the generic type specifier ...



A TreeNode implementation like this will give you the ability to have async loads of children and so forth, something thats currently handled by a confusing mix of loaders, binders and stores.
I found the mix of loaders, binders and stores confusing at first. But after making a sketch on how they are tied together as well as using them on paged tables I kinda like them, they offer reasonable flexibility. You can quite easily drop in your own DataProxy if needed. It was also straightforward to make a memory paged custom data store. But then, if you don't like the Store/Model stuff that might not be relevant.


6. Events and ListenersAgree, my AppEvents file reminds of old days doing Windows programming....
There were some other discussions on this, more specifically a proposal for how enum based events could be done. I'm not aware of status.



tabPanel.addListener(Events.Remove, new Listener<ContainerEvent<TabPanel, TabItem>>() {
...
});

This is crazy. I'd much rather have correctly typed listeners and explicit add...Listener methods rather than addListener. For example:

Yes, another example on why many people are put off by Java generics...

It sure looks kinda ugly. Maybe it's just me but after getting used to generics your example line reads perfectly well. "Create a listener for removals of TabItems from the TabPanel, the Listener receives a ContainerEvent wich has access to the tabpanel itself as well as the removed tabitem.

Do you mean that instead of this you want convenience methods for all possible listener s? , like tabPanel.addRemoveItemListener(TabItem i) ?



public interface Model ... {
void addChangeListener(ChangeListener changeListener);
}

public interface ChangeListener {
void propertyChanged(PropertyChangeEvent event);
}
This is for model objects and all well, looks like the Gwittir stuff. But I don't see how this applies to your generic example above.



7. Inconsistent Generics

Theres an awful lot of code that partially uses generics. For example, BaseTreeModel.adopt() has a parameter of type TreeModel, not TreeModel<something>. You'll find examples like this and assigning generic arguments to non-generic data members all over the place.
Agreed, a clean-up up is necessary. Also, there are still classes with public properties sticking around.


8. Conclusion

Theres some pretty scary stuff in here and I know I've only scratched the surface. The current release is 1.0rc2 and I really have to consider this a political 1.0 release. Its nowhere near ready for primetime. Once 1.0 is release this bizarre API is basically set in stone. Hell, its almost set in stone by the RC designation.
I totally disagree, there is nothing scary here. On the contrary, everything is transparent and IMHO things are working pretty darn well.

On a side note, ExtGWT has generally lower performance compared to plain GWT. As far as I understand GWT wraps pure HTML constructs. So I believe standard GWT widgets will always be bound by HTML and never be as advanced as ExtGWT widgets unless GWT departs from this principle, right?


On the project I'm working on we were using MyGWT and quite liked it. It was a natural move to Ext-GWT but we're being forced to abandon it entirely as we learn more about it in favour of vanilla GWT. Sure we won't have ContentPanels that way but we won't have BaseTreeModel<BaseTreeModel> either. A non-generic interface is preferable to a badly designed and inconsistent generic interface and thats what Ext-GWT is.
Falling back to plain GWT? Good luck writing your own binding stuff, advanced tables, MVC classes, and all the other stuff missing from GWT. Many development projects did just that during two 1-2 years of GWT existence, with a great cost.
Gwittir is definitely not ready for prime time despite its slick binding stuff, bindings are only implemented for a couple of widgets and the whole site resembles a proof-of-concept thing, albeit a powerful proof. It's also GPL without a commercial offering so far.
Then there is Ext-JS with great widgets, but being a JavaScript wrapper I assume any binding and MVC stuff is gone, and no tracing of GUI code in hosted mode...

Plain GWT would sure be a lot nicer if Google included a data binding mechanism like Gwittir's , data loading abstractions, and advanced tables and lists.

I am curious what, except for speed wich you haven't mentioned, was better in MyGWT? MyGWT also used the Model stuff, although it wasn't a interface at that time.
The binding mechanism in MyGWT was a JFace implementation, I assume that is what you are referring to? But as far as I remember that mechanism also relied on the Map based introspection provided by the BaseModel objects, similar like today... ?

cheers!

Cameron Braid
9 Jul 2008, 5:56 AM
You raise lots of good points.

FYI I am not an Ext employee, nor am I contracted by them. I am a sole trader.

I use GXT in a web application and I am try to help Darrell make GXT better.

Regards

Cameron Braid

darrellmeyer
9 Jul 2008, 9:02 AM
In Swing, models are basically just POJOs with relevant adapters like TableModel and frankly instead of:

model.get("dateOfBirth")
model.set("dependants", 2)

I prefer:

model.getDateOfBirth()
model.setDependants(2)
The get and set methods are not designed to be called directly. The intent is for you to create model subtypes that have the appropriate getters and setters. The callers do not need to be aware that the values are stored in a map. The library uses the set and get methods internally. You are free to use your typed getters and setters in your application. If you follow this model, it really does not matter how generics are used internally.

cletus
9 Jul 2008, 5:20 PM
Well who doesn't? But isn't the real question how to support POJO models in a databinding?

Thats easy: you leave it up to implementor. As any Swing programmer will tell you, it doesn't take a lot to fire change events when you need to. Why can't I write a POJO with set() methods that call fireEvent() myself? Its fine to have a Map based alternative that does this for you. The problem is the GXT widgets force you to use it.

Think of this as being like a CMP vs BMP in the EJB sense.


I am not 100% sure but I think you're not correct. Isn't cascading of update events from child to parent only applicable for children of a BaseTreeModel object (as in myTreeModel.add(new MyThreeModelChild) )No. Look at the code for BaseModel:

@Override
public <X> X set(String name, X value) {
Object oldValue = super.set(name, value);
notifyPropertyChanged(name, value, oldValue);
return (X)oldValue;
}

BaseModelData.set() will call setNestedValue(). If it finds a ModelData instance in a nested property it will call set() on it. If that ModelData is itself a BaseModel it too will trigger an event.


Also there are, or at least was, issues with the GWT RPC/compiler when using plain BaseModel objects that return collection of other BaseModel objects. I ended up converting all my models to TreeModels to get around this, hence lots of model classes specifying themselves in the generic type specifier ...Nice to know. In my case I was building the model on the client based on resposnes from RPC calls rather than sending the entire model at once so that wasn't an issue.


Do you mean that instead of this you want convenience methods for all possible listener s? , like tabPanel.addRemoveItemListener(TabItem i) ?I mean something:

class MyTabItem extends TabItem {
}

class Container<T extends Widget> {
public <C extends Container> void addRemoveListener(RemoveListener<C, T> listener) { }
public void add(T item) { }
public void remove(T item) { }
}

class TabPanel<T extends TabItem> extends Container<T> {
}

interface RemoveEvent<T extends Container, U extends Widget> extends Event {
T getContainer();
U getWidget();
}

interface RemoveListener<T extends Container, U extends Widget> {
void onRemove(RemoveEvent<T, U> event);
}

interface Event {
}

which allows you to do this:

TabPanel<MyTabItem> tabPanel = new TabPanel<MyTabItem>();
tabPanel.add(new MyTabItem());
tabPanel.addRemoveListener(new RemoveListener<TabPanel, MyTabItem>() {
public void onRemove(RemoveEvent<TabPanel, MyTabItem> event) { }
});


I am curious what, except for speed wich you haven't mentioned, was better in MyGWT? MyGWT also used the Model stuff, although it wasn't a interface at that time.MyGWT had the same Model issue but the interface was cleaner.

cletus
9 Jul 2008, 5:22 PM
The get and set methods are not designed to be called directly. The intent is for you to create model subtypes that have the appropriate getters and setters. The callers do not need to be aware that the values are stored in a map. The library uses the set and get methods internally. You are free to use your typed getters and setters in your application. If you follow this model, it really does not matter how generics are used internally.

Yes it does. Model exposes set() and get(), which is why I referred to typed getters and setters are a placebo.

zaccret
10 Jul 2008, 12:17 AM
The callers do not need to be aware that the values are stored in a map. The library uses the set and get methods internally.

Actually, there is at least one exception : displayProperty. The model must call set(displayProperty,displayValue) See http://extjs.com/forum/showthread.php?t=38371

Grandiosa
10 Jul 2008, 1:34 AM
Thats easy: you leave it up to implementor. As any Swing programmer will tell you, it doesn't take a lot to fire change events when you need to. Why can't I write a POJO with set() methods that call fireEvent() myself? Its fine to have a Map based alternative that does this for you. The problem is the GXT widgets force you to use it.
POJOs that fire change events is the easy part of databinding, even more so if you use the standard Java classes for it instead of writing your own ChangeEventSupport, like for example the GWTx library.
The hard part is doing the actual binding. By requiring bindable POJOs you implicitly require a completely new introspection mechanism in ExtGWT. Ignoring converters and validators for now what you and I want to do is something like this:

Binding binding = new Binding(yourModel, "DateOfBirth", birthTextField) or perhaps

Binding binding = new Binding(yourModel, "Children", childrenListBox)

With Java and reflection it's "straightforward" to make this. Not so in Javascript. ExtGWT takes the "easy route" requiring all model objects to be maps.
It's my impression that making a smart introspection mechanism has never been a focus in ExtGWT. I would really like such engeneering in ExtGWT, despite the fact that my app is gonna run in a freakin browser.. Who knows, if enough ExtGWT users asks for it it might show up on the radarscreen for a future release, like version 1.5 or 2.0 :-)


Think of this as being like a CMP vs BMP in the EJB sense.That analogy is of no help to me.



No. Look at the code for BaseModel:
...
BaseModelData.set() will call setNestedValue(). If it finds a ModelData instance in a nested property it will call set() on it. If that ModelData is itself a BaseModel it too will trigger an event.
Aah, sorry, I mixed the nested stuff with the children/cascading stuff of TreeModels. Your example was:



b.set("blah.count", 5);
You can turn of notification of the "blah" listeners by doing "allowNestedProperties = false" in the constructor of its containing model.
If you just want to update the nested model containing the count attribute and prevent notification of "blah" listeners you will have to let go of the nested syntax and do it the old way:



nestedModel = b.get("blah") ;
nestedModel.set("count",5)

zaccret
10 Jul 2008, 3:31 AM
With Java and reflection it's "straightforward" to make this. Not so in Javascript. ExtGWT takes the "easy route" requiring all model objects to be maps.
It's my impression that making a smart introspection mechanism has never been a focus in ExtGWT.
Right. But above all it is not a focus in GWT. I guess this is because of :
- performance issue,
- the hugeness of the feature beside the gains
GWT optimizations preclude general support for reflection.

Actually, I haven't thought about binding (object <-> form field) and now I don't see any other solution than the Map stuff for it.

sheesh-kebab
11 Jul 2008, 4:00 PM
I've written plenty of swing stuff in my time, and I rarely had to use maps to generalize models for tables and other widgets (Are maps are great for writing generalized/metadata driven apps - however for your typical development it's an overkill).

For example, in swing, the typical way to populate tables goes something like this

http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/table/TableModel.html

Object getValueAt(int row, int col){
if(col==0){
return people.get(row).getFirstName();
}if(col==1){
return people.get(row).getLastName();
}else{
throw new RuntimeException("Invalid column " + col);
}
}

and similarly for setValueAt(int row, int col, Object value)...

For generalized filtering/sorting/column or node reordering features in widgets, one might write some specialized code around column indices and maybe require using some custom sortable/filterable table models (again I've developed them before easily), but it's usually not such a big deal and doesn't require drastic departure into the domain of metadata driven models. Also, typically reflection is not necessary...the simpler the better.

Rich GUI development has been around forever and we should really try to learn from its experience. There are some good ideas there...

darrellmeyer
14 Jul 2008, 6:19 AM
I have posted a new blog entry, detailing new Java Bean support with Ext GWT. With these changes, you can send any Java Bean over the wire and use them within the Store and Binder API.

http://extjs.com/blog/2008/07/14/preview-java-bean-support-with-ext-gwt/

The code will be included in the 1.1 release. Feel free to let me know if you have and feedback on the approach. This code has not been released so there is still a small window for making changes.

joshb
14 Jul 2008, 9:24 AM
Darryl,

A couple of questions:

While the bean doesn't need to change, it MUST have been declared serializable, correct?

Secondly, is it possible to restrict the data being transfered, i.e. leave out a large list of information? I don't really know how this gets implemented, so I apologize if these seem like silly questions.

Josh

darrellmeyer
14 Jul 2008, 9:50 AM
While the bean doesn't need to change, it MUST have been declared serializable, correct? If you are using the bean with RPC, yes, it must implement Serializable.


Secondly, is it possible to restrict the data being transfered, i.e. leave out a large list of information? I don't really know how this gets implemented, so I apologize if these seem like silly questions.New BeanModel instances are created on the client with your java bean. The new bean code is not involved with what data you send to the client using RPC, it just wraps the bean instance. You are responsible for controlling what data is sent from the server.

zaccret
14 Jul 2008, 1:02 PM
I have posted a new blog entry, detailing new Java Bean support with Ext GWT. With these changes, you can send any Java Bean over the wire and use them within the Store and Binder API.

http://extjs.com/blog/2008/07/14/preview-java-bean-support-with-ext-gwt/

The code will be included in the 1.1 release. Feel free to let me know if you have and feedback on the approach. This code has not been released so there is still a small window for making changes.

Hey, Darell, I love this new !!! I'm impatient to test that and leave the intrusive ModelData interface away. Great job !

Grandiosa
14 Jul 2008, 1:56 PM
I really like surprises! Looking forward to test this when I'm back from holiday in a few weeks... Great job!

firejack
28 Aug 2008, 3:32 AM
To defend the GXT implementation - there needs to be a reliable way to serialize your models rapidly to JSON in order to do the Java to JS conversion for you on the fly. I agree with Daryll that the internals shouldn't matter - so perhaps those methods should be protected methods on the classes to actually discourage people from using them - my guess is there are problems there due to the need to consume these methods appropriately using the utilities in other packages.

I am just beginning to crack the nut that is the GXT source code - but I can tell you there is a lot of really interesting complexity in handling all this JNI -> JS -> JSON -> AJAX -> Servlet -> Java transition stuff and I can see that the performance and smoothness is superior to the google code attempt to do the same. I have worked with both.

On the generics point - I agree, less is more. Generics solves some specific problems like typesafe collections reallly well (it was needed). A lot of other uses - I am still struggling with the point - seems like there were already good solutions for those problems with better design of your code (albeit sometimes adding interfaces and classes that could be avoided I suppose - but it made the code clean and logical). Generics is starting to make Java feel like a scripting language - too much freedom to obfuscate whats going on or what should be allowed to happen. That is a criticism for Sun though, and they are sick of hearing from me from the 90s. :)

erdahl
9 Sep 2008, 4:35 PM
Hi. I guess I may be coming into this thread a bit late....

As a former GWT-Ext user, I'm wondering if there is a fundamental (design) reason why GXT can't support a similar API as GWT-Ext? I found GWT-Ext to be quite usable from a programming perspective. (Granted, there are some minor issues I had with GWT-Ext).

In particular, I'm trying to understand the need for these generics. GWT-Ext didn't need them. Are they there for speed? From a newbie's perspective (who also hasn't found any tutorials on their usage and doesn't see much in the javadocs), it looks very similar to hacks people may do for advanced C++ templates (policies, etc.).

zaccret
10 Sep 2008, 12:35 AM
From a newbie's perspective (who also hasn't found any tutorials on their usage and doesn't see much in the javadocs)

+1 on that point. It is true that there is a lack of javadoc about generics and they are not all used in the samples.