Ext

Preview: Java Bean support with Ext GWT

July 14, 2008 by Darrell Meyer

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 create bean 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.

8 Responses to “Preview: Java Bean support with Ext GWT”

  1. Gary J

    Nice work, just got it from svn and it works great!

  2. hebo

    OH~ it’s like great!

  3. Ext JS - Blog

    [...] Java bean support [...]

  4. Uros Trebec

    Hi,

    I’m trying to use GXT 1.1alpha3 and can’t get the table equivalent of “grid example” working.

    Did anything change in the mean time?

    I’m using it this order:

    BeanModelReader reader = new BeanModelReader();
    BasePagingLoader loader = new BasePagingLoader(proxy, reader);
    loader.load(0, 20);
    ListStore store = new ListStore(loader);
    final PagingToolBar toolbar = new PagingToolBar(20);
    toolbar.bind(loader);
    new TableBinder(table, store);

    Anything terrebly wrong?

  5. Jimmy

    Any idea on how to wire Enteprise Java Beans over the wire?
    First problem is that the EJB wont compile in gwt becouse they relate to annotatioons in javax.persistence.*;
    I then made fake annotation files, that made the gwt js compile and run.
    But then the gwt-servlet fails to serialize the beans for transmission

    This error is shown in console:
    Caused by: com.google.gwt.user.client.rpc.SerializationException: Type ‘oracle.toplink.essentials.internal.indirection.UnitOfWorkQueryValueHolder’ was not included in the set of types which can be serialized by this SerializationPolicy or its Class object could not be loaded. For security purposes, this type will not be serialized.

  6. Ext JS - Blog

    [...] 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. More information can be found in this blog post. [...]

  7. Jeroen

    I’m trying to get the Java Bean stuff working.
    But when I follow your example using the factory the system won’t compile.

    This is caused by the fact that the GWT compiler can’t find the BeanModelLookup implementation which is made at run-time, but I need it to create instance of my model.

    At the following code to a project that is not build with the GXT.gwt.xml.

    BeanModelFactory factory = BeanModelLookup.get().getFactory(MyJavaBean.class);
    BeanModel model = factory.createModel(myJavaBean);

  8. Jeroen

    Hereby the build error,
    Scanning for additional dependencies: jar:file:/G:/gwt/gxt-1.1/gxt.jar!/com/extjs/gxt/ui/client/data/BeanModelLookup.java
    Computing all possible rebind results for ‘com.extjs.gxt.ui.client.data.BeanModelLookup’
    Rebinding com.extjs.gxt.ui.client.data.BeanModelLookup
    Invoking
    [ERROR] Class com.extjs.gxt.ui.client.data.BeanModelLookup not found.
    java.lang.NullPointerException
    at com.extjs.gxt.ui.rebind.core.BeanModelGenerator.getMarkerBean(BeanModelGenerator.java:169)
    at com.extjs.gxt.ui.rebind.core.BeanModelGenerator.generate(BeanModelGenerator.java:53)
    at com.google.gwt.dev.cfg.RuleGenerateWith.realize(RuleGenerateWith.java:51)
    at com.google.gwt.dev.shell.StandardRebindOracle$Rebinder.tryRebind(StandardRebindOracle.java:116)
    at com.google.gwt.dev.shell.StandardRebindOracle$Rebinder.rebind(StandardRebindOracle.java:61)
    at com.google.gwt.dev.shell.StandardRebindOracle.rebind(StandardRebindOracle.java:166)
    at com.google.gwt.dev.GWTCompiler$DistillerRebindPermutationOracle.getAllPossibleRebindAnswers(GWTCompiler.java:195)
    at com.google.gwt.dev.jdt.WebModeCompilerFrontEnd.doFindAdditionalTypesUsingRebinds(WebModeCompilerFrontEnd.java:128)
    at com.google.gwt.dev.jdt.AbstractCompiler$CompilerImpl.process(AbstractCompiler.java:150)
    at org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:392)
    at com.google.gwt.dev.jdt.AbstractCompiler$CompilerImpl.compile(AbstractCompiler.java:84)
    at com.google.gwt.dev.jdt.AbstractCompiler$CompilerImpl.compile(AbstractCompiler.java:180)
    at com.google.gwt.dev.jdt.AbstractCompiler$CompilerImpl.access$400(AbstractCompiler.java:70)
    at com.google.gwt.dev.jdt.AbstractCompiler.compile(AbstractCompiler.java:493)
    at com.google.gwt.dev.jdt.WebModeCompilerFrontEnd.getCompilationUnitDeclarations(WebModeCompilerFrontEnd.java:73)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.(JavaToJavaScriptCompiler.java:277)
    at com.google.gwt.dev.GWTCompiler.distill(GWTCompiler.java:353)
    at com.google.gwt.dev.GWTCompiler.run(GWTCompiler.java:564)
    at com.google.gwt.dev.GWTCompiler.run(GWTCompiler.java:554)
    at com.google.gwt.dev.GWTCompiler.main(GWTCompiler.java:214)
    [ERROR] Errors in ‘jar:file:/G:/gwt/gxt-1.1/gxt.jar!/com/extjs/gxt/ui/client/data/BeanModelLookup.java’
    [ERROR] Line 17: Failed to resolve ‘com.extjs.gxt.ui.client.data.BeanModelLookup’ via deferred binding

Leave a Reply

To prove that you're not a bot, please answer this question:



© 2006-2008 Ext, LLC