The Ext GWT Store and Binder API work with ModelData instances. The primary goal of ModelData is to provide a type of “introspection” as GWT does not allow runtime inspection of Java objects. You can query ModelData for a list of properties it contains, and these properties can be retrieved and set using the parameter name with the get and set methods.
Although this approach works, it forces you to either implement the ModelData interface in your Java Beans or extend the Ext GWT base classes that implement the ModelData interface. What is missing is a way to use your Java Beans as is, without having to extend the Ext GWT base classes or implement an “invasive” interface.
With the 1.1 release of Ext GWT, it is possible to use any Java Beans in the Store and Binder API. This allows you to send your Java Beans from server to client using GWT RPC.
Java Bean support is provided by dynamically creating new BeanModel instances using any bean. The new type will “wrap” the bean, and all get and set calls on the model will be delegated to the underlying bean. Also, the original bean is available via the new bean model instance. The new model instances are created using a GWT Generator. Basically, the generator allows “new” types to be created at compile time using GWT.create(). The GXT generator will create a BeanModelFactory than can create new BeanModel instances from a Java Bean.
Identifying Java Beans
There are 2 ways of identifying Java Beans. The first method requires a new interface that extends BeanModelMarker and uses annotations. This method does not require the JavaBean to be modified. With the second method, your Java Bean implements the BeanModelTag interface.
BeanModellMarker Interface
The first step to enable Java Bean support is to identify the Class you would like to “adapt”. Rather than specifying the class directly, a new interface is created that extends BeanModelMarker. Then, a @BEAN annotation is added to the interface to identify the actual bean. This approach is beneficial, as it allows a single deferred binding rule to be used to identify your bean. Also, by using a marker interface, other configuration information can be specified by annotations.
public class Customer implements Serializable {
private String name;
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@BEAN(Customer.class)
public interface CustomerBeanModel extends BeanModelMarker {
}
BeanModelTag Interface
With this method, a new interface is not required as you tag the Java Bean directly. This means your beans will have a reference to a GXT interface.
public class Customer implements BeanModelTag, Serializable {
private String name;
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
BeanModelLookup
BeanModelLookup is used to obtain a BeanModelFactory instance for a given bean type. You will use the BeanModelLookup singleton to obtain a BeanModelFactory for your given bean. The BeanModelFactory can be used to create new bean model instances from your bean instances.
BeanModelFactory factory = BeanModelLookup.get().getFactory(Customer.class);
With the factory, you are able to create new BeanModel instances that wrap your bean.
Customer c = new Customer();
c.setName("Darrell");
BeanModel model = factory.createModel(c);
BeanModelReader
It is common to use the GXT data loading API to retrieve remote data and populate a Store. The BeanModelReader can be used to handle creating new model instances from the beans being returned from the data proxy. With this approach, you can return any Java Beans from the RPC call. BeanModelReader will lookup the factory given the type of the objects being returned from the data proxy.
Store
When using this approach, the type of objects in the store will be the dynamically created types that were created based on the bean. These objects will extend BeanModel. BeanModel provides access to the “wrapped” bean via the getBean method.
Customer customer = (Customer)model.getBean();
Grid Example
Here is a snippet of code from the Explorer demo. It demonstrates uses a BeanModelReader with a Grid.
// gwt service
final ExplorerServiceAsync service = (ExplorerServiceAsync) Registry.get("service");
// proxy and reader
RpcProxy proxy = new RpcProxy() {
@Override
public void load(Object loadConfig, AsyncCallback callback) {
service.getCustomers(callback);
}
};
BeanModelReader reader = new BeanModelReader();
// loader and store
ListLoader loader = new BaseListLoader(proxy, reader);
ListStore<BeanModel> store = new ListStore<BeanModel>(loader);
loader.load();
// column model
List<ColumnConfig> columns = new ArrayList<ColumnConfig>();
columns.add(new ColumnConfig("name", "Name", 200));
columns.add(new ColumnConfig("email", "Email", 100));
columns.add(new ColumnConfig("age", "Age", 50));
ColumnModel cm = new ColumnModel(columns);
Grid<BeanModel> grid = new Grid<BeanModel>(store, cm);
grid.setAutoExpandColumn("name");
grid.setWidth(400);
grid.setAutoHeight(true);
grid.setBorders(true);
Summary
The new Java Bean support allows easy data integration of your existing Java Bean objects. Sending any Java Bean over the wire is possible, and Ext GWT can createbean model instances on the client.
These features will be available with the 1.1 release of Ext GWT. For those with access to SVN, the working code is in the trunk.