Functional* Reactive Framework for GWT


Two goals

  1. MVP Automation
  2. Reactive Data Binding

MVP: Purpose

  1. Unit test busines logic
  2. Quickly, e.g. no browser

public void testNameIsRequired() {
  assertThat(v.nameErrors(), hasError("Required"));

public void testServerResponse() {
  doSubmitResult("some error from server");
  assertThat(v.nameErrors(), hasError("some error..."));

MVP: Manual Workflow

1. Change somePage.ui.xml

<gwt:TextBox ui:field="foo" />

2. Change IsSomePageView

public interface IsSomePageView {
  HasText getFoo();

3. Change GwtSomePageImpl

TextBox foo;

public HasText getFoo() {
  return this.foo;

4. Update presenter

MVP: Tessell Workflow

1. Change somePage.ui.xml

<gwt:TextBox ui:field="foo" />

2. Change IsSomePageView interface

public interface IsSomePageView {
  IsTextBox getFoo();

3. Change GwtSomePageView implementation

GwtTextBox foo;

public IsTextBox getFoo() {
  return this.foo;

4. Update presenter

MVP: Result

Fast, no-boilerplate workflow


Reactive Databinding

  1. Two-way binding between view and model
  2. Support for collections, derived values
  3. Functional*
    • Caveat: need lambdas to be "functional"

Databinding: Swing Approach

Handler spaghetti code

textBox.addChangeHandler(new ChangeHandler() {
  public void onChange() {

model.addChangeHandler(new ChangeHandler() {
  public void onChange() {

Databinding: Swing with Lambdas

textBox.addChangeHandler(e -> model.setName(textBox.getValue()));

model.addChangeHandler(e -> textBox.setValue(model.getName()));

Databinding: Tessell

Think declaratively

public void onBind() {

With collections

binder.bind(model.children).to(view.panel(), new ListViewFactory() {
  public IsWidget create(ChildDto child) {
    return new ChildPresenter(child);

Conditional logic


On user input

    binder.onKeyDown(view.editBox(), KEY_ESCAPE).set(editing).to(false);

Caveat: We need properties

Given a DTO:

class ChildDto {
  public String name;
  public Dollars salary;

How would this work?

ChildDto c = new ChildDto();
binder.bind(c.name).to(view.textBox()); // ??

When ChildDto.name changes?

Caveat: We need properties

Build models object:

class ChildModel {
  public StringProperty name = stringProperty("name");
  public DollarsProperty salary = dollarsProperty("salary");

Now we can see when name changes:

ChildModel c = new ChildModel();
c.name.addPropertyChangedHandler() {
  public void onChange() {

// Or, shorter way

Caveat: We need models

Sounds like more boilerplate?

Answer: Code generation

dtonator (http://www.dtonator.org)

  domain: Child
  properties: id, name
  tessellModel: true


ChildDto dto = new ChildDto(1, "c1");
ChildModel model = new ChildModel(dto);
model.name.get(); // returns c1


Derived values

StringProperty name = stringProperty("name", "n1");
IntegerProperty max = integerProperty("max", 10);
Property<String> shortName = new DerivedProperty<String>() {
  public String getDerivedValue() {
    return name.get().substring(0, max.get());

And soon:

binder.bind(() -> {
  name.get().substring(0, max.get())



Minimal Places

public class MyPresenter {
  @GenPlace(name = "myPlace", async = false)
  public static void onRequest(MyPlaceRequest req, AppContext c) {
    c.show(new MyPresenter(...));

Command Pattern Code Generation

public class SaveClientSpec {
  ClientDto dto;
  String error;


async.execute(new SaveClientAction(dto), SaveClientResult r -> {
  r.getError(); // logic

Interfaces and Stubs for widgets

Out of the box:

  • IsTextBox, StubTextBox
  • IsListBox, StubListBox
  • IsFlowPanel, StubFlowPanel

Tessell Overview: Benefits

  1. Mature, stable code (4+ years, 6800 commits, 361 releases)
  2. All core functionality (data binding, etc.) is Java, so presenters can be unit tested and it will exercise all binding/etc. logic
  3. First-class support for common idioms
    • All properties have validation rules
    • All properties have "touched" state

Tessell Overview: Weaknesses

  1. No bootstrap/archetype to get started
    • Day one setup is going to suck
    • Day two on is going to be fun
  2. Does not take "Rails"/batteries-included approach
    • Has gwt-dispatch-style RPC, optional
    • Has pre-Activities & Places places, optional