Skip to main content

Exploring GWT 4: Creating the Property Adapter

Posted by mjeffw on September 25, 2008 at 5:39 AM PDT

GWT's deferred binding is triggered with this call:

   PropertyAdapter<Foo> fooAdapter = (PropertyAdapter<Foo>) GWT.create(Foo.class);

Or, more generally:

   Object obj = GWT.create(Class aClass);

The developer passes a class to the GWT.create() method and GWT returns an object that extends that class (or, if aClass represents an interface, GWT returns an object that implements the given interface). This is accomplished either by replacement or generation. Replacement is used when the returned class can be written ahead of time, while generation invokes GWT's code generation framework to build the source code of a new class, compile it, and return it.

For our property adapter, we need to generate code because we need to detect all the "properties" (in the java.beans sense) on the original class and wrap Property objects around each. This would be hard to do without reflection, but GWT has methods that allow you to examine the source code of your classes and generate new code based on that source.

In my design, PropertyAdapter is the interface that is used by code that is interested in PropertyChangeEvents on the fields of the underlying property source class. GWT.create() will return an object that implements this interface.

So, what does the source of PropertyAdapter look like? Here's my implementation:

public interface PropertyAdapter<T>
{
   void setPropertySource(T source);
   Property<?> get(String propertyName);
}

The class that we need to generate must be able to determine the name and type of each attribute of the underlying property source class, and generate a Property object for each. That property object should be stored in a Map keyed by the property's name, so that calls to PropertyAdapter.get("foo") will return the correct Property.

I find it most helpful to write out an example before jumping headfirst into the code generation. Let's take our original source class:

class Person 
{
   private String firstName;
   private String middleName;
   private String lastName;

   public String getFirstName() { return firstName; }
   public void setFirstName(String name) { firstName = name; }

   public String getMiddleName() { return middleName; }
   public void setMiddleName(String name) { middleName = name; }

   public String getLastName() { return lastName; }
   public void setLastName(String name) { lastName = name; }
}

This class has three properties: firstName, middleName, and lastName. I plan to recognize properties in the source class by looking for Java beans-style getters and setters. A PropertyAdapter for this class might look like this:

public class Person_PropertyAdapter implements PropertyAdapter<Person>
{
   private Person source;
   private java.util.HashMap<String, Property<?>> map = new java.util.HashMap<String, Property<?>>();

   public Property<?> get(String propertyName)
   {
      return map.get(propertyName);
   }

   public void setPropertySource(Person source)
   {
      this.source = source;
      createProperties();
   }

   private void createProperties()
   {
      map.clear();

      Property<String> firstName = new Property<String>("firstName", new Accessor<String>() {
         public String get() { return source.getFirstName(); }
         public void set(String newValue) { source.setFirstName(newValue); }
      });
      map.put(firstName.getName(), firstName);

      Property<String> middleName = new Property<String>("middleName", new Accessor<String>() {
         public String get() { return source.getMiddleName(); }
         public void set(String newValue) { source.setMiddleName(newValue); }
      });
      map.put(middleName.getName(), middleName);

      Property<String> lastName = new Property<String>("lastName", new Accessor<String>() {
         public String get() { return source.getLastName(); }
         public void set(String newValue) { source.setLastName(newValue); }
      });
      map.put(lastName.getName(), lastName);
   }
}

As you can see, the class is pretty simple. The setPropertySource() method saves a copy of the source object, then creates an instance of a Property object for each Java Bean property in the source class. This Property is stored in a Map using the property's name as the key. The get() method simply returns the Property bound to the passed name from that Map.

At this point I had my interface that I was going to apply GWT's deferred binding to, and I knew what the generated source code should look like. So what is left is to actually write the code to generate that source.

In the next post I show how to use GWT's generators to create the source code for my Person_PropertyAdapter class.

Related Topics >>

Comments

You can still look at the Cached version here : http://209.85.129.132/search?q=cache:rT7Cx8nAsOoJ:weblogs.java.net/blog/... You can mark methods or types or properties with annotations in GWT and analyse them at code-generation time, it's not 100% java neither, but marking the binded fields / methods by annotation is really cool :) And thanks for the great posts jeff ;)

Yeah, sorry. Events caught up with me this month. I'll get the next post out by Monday. Thanks for reading!

Looking forward to the next post.

scotty69, an interesting idea: basically using the annotation processor like a pre-processor. It may be possible to do that and make sure it hooks into GWT, but its not obvious to me how it would work. If you could manage to get the annotations processor out of the GWT source path (so you could use the parts of Java GWT does't support, like Reflection), and make this approach work in either hosted or web mode without a lot of hacking (for instance, doing a two-pass compile) it may work. I'd have to give it some thought or try it out. Maybe another reader has already tried it and can give his view on how that worked? As for this series, I'm not too concerned about replicating the wheel, since this is all just experimentation to see how things like deferred binding and GWT generators work.

Interesting! But what is the reason for generating the source code with a GWT generator instead of a more generic Java annotation processor (and then feeding the generated source into the GWT compiler)? Couldn't be the generated code useful on the server-side as well? (Basically your approach is to generate type-safe first-class properties, which actually should be provided by the Java language itself, but that's another story).