Intro to Errai 4.0

A type-safe and declarative programming model for the browser

Why Errai?

More code is more work

  • It's better to have less code that clearly expresses intent
  • Boilerplate code is more than an annoyance — it's a burden

Why Errai?

Large projects mean large compile times

  • Separate GWT modules must be compiled together
  • This gives reusability but doesn't help reduce compile times or give runtime flexibility

What is Errai?

Declarative good, boilerplate bad

What is Errai?

Declarative client-side features

  • Client-side dependency injection (consistent with CDI)
  • Client-side templating
  • 2-way data-binding
  • Dynamic runtime module support (using JsInterop)

Errai IoC

Dependency Injection

  • Dependency injection in Errai is consistent with CDI
  • Dependencies are resolved to beans
  • Both the type and qualifier annotations determine what dependencies a bean satisfies

Errai IoC

A simple bean

public class MySimpleServiceImpl implements MySimpleService {

  @Override
  public void doTheThing() {
    // ...
  }
}
public class ServiceUser {

  @Inject
  MySimpleServiceImpl service;
}

A bean with a dependency

public class ServiceUser {

  @Inject
  MySimpleService service;
}

Errai IoC

public class ServiceUser {

  final MySimpleService service;

  @Inject
  public ServiceUser(MySimpleService service) {
    this.service = service;
  }
}
public class ServiceUser {

  MySimpleService service;

  @Inject
  public void setService(MySimpleService service) {
    this.service = service;
  }
}

Constructor and setter injection

Errai IoC

Supports more CDI features

  • @Alternative
  • @Specializes
  • @Produces
  • Circular dependencies

Errai UI

Declarative templating

  • Binds widget and element fields of Java classes to elements in an HTML template
  • Template files can be HTML fragments or full pages
  • The HTML file is the template
  • The Java class is a templated bean

Errai UI

How does it work?

  • This @Templated class has a two @DataFields
  • The text field is injected, but the submit field is not
@Templated
public class MyForm extends Composite {

  @Inject
  @DataField
  TextBox text;

  @DataField
  Button submit = new Button();
}
<div>
  <input data-field="text" type="text" />
  <input data-field="submit" type="button" />
</div>
  • This fragment should be MyForm.html in the same package
  • The input element has a data-field that matches the name of the field above
  • We could also have used id or class attributes for binding

Errai UI

Declaring event handlers

  • The onClick method is registered as a click handler on the submit button
  • You can declaratively register handlers for any event type, on any @DataField
@Templated
public class MyForm extends Composite {

  @Inject
  @DataField
  TextBox text;

  @DataField
  Button submit = new Button();

  @EventHandler("submit")
  private void onClick(ClickEvent event) {
    // Do the thing...
  }
}

Errai UI

Template inception

  • @Templated bean is a widget
  • You can use it as a @DataField inside other @Templated beans
  • Content in a data-field is replaced by HTML from MyForm
@Templated
public class MyFormView extends Composite {

  @Inject
  @DataField
  MyForm form;
}
<div>
  <div data-field="form">
    <!--
    The contents of this div will be replaced
    at runtime with the html fragment for MyForm
    -->
    <span>I am content that won't be rendered!</span>
  </div>
</div>
<div>
  <div data-field="form">
    <input data-field="text" type="text" />
    <input data-field="submit" type="button" />
  </div>
</div>

Errai UI

Designer templates

@Templated("DesignerTemplate.html#contact")
public class ContactView extends Composite {

}
<!DOCTYPE html>
<html>
  <head>
    <title>Designer Template</title>
  </head>
  <body>
    <navbar>
      <ul>
        <li><a href="#home">Home</a></li>
        <li><a href="#contact">Contact</a></li>
    </navbar>
    <section id="home">
      <h1>Home</h1>
      <p>This is the home section.</p>
    </section>
    <section id="contact">
      <h1>Contact</h1>
      <p>This is the contact section.</p>
    </section>
  </body>
</html>















    <section id="contact">
      <h1>Contact</h1>
      <p>This is the contact section.</p>
    </section>

Errai Data-Binding

What is data-binding?

  • Data-binding keeps Java bean property values synchronized with widget/element values
  • Changes in widgets are reflected in model and vice-versa
  • Can be used in @Templated beans

Errai Data-Binding

How does it work?

  • This class is @Bindable with two properties
@Bindable
public class User {

  private String username;
  private Date dateOfBirth;

  public void setUsername(String username) {
    this.username = username;
  }

  public String getUsername() {
    return username;
  }

  public void setDateOfBirth(Date dateOfBirth) {
    this.dateOfBirth = dateOfBirth;
  }

  public Date getDateOfBirth() {
    return dateOfBirth;
  }
}

Errai Data-Binding

  • The name and dob fields are @Bound
  • They are kept in sync by binder
@Templated
public class NewUserForm extends Composite {

  @Inject @AutoBound
  DataBinder<User> binder;

  @Inject
  @Bound
  @DataField
  TextBox username;

  @Inject
  @Bound(property="dateOfBirth")
  @DataField
  DateBox dob;

  @Inject
  @DataField
  Button submit;

  @EventHandler("submit")
  private void onClick(ClickEvent event) {
    User newUser = binder.getModel();
    // These will be true
    assert newUser.getUsername().equals(username.getValue());
    assert newUser.getDateOfBirth().equals(dob.getValue());
    // ...
  }
}

Errai Data-Binding

User user = binder.getModel();
// This updates the value in the TextBox widget
user.setUsername("Max");

// So this must be true
assert username.getValue().equals("Max");

Going the other direction

Errai Data-Binding

Binding a list of values

  • The widget used for each item must be a type implementing HasModel for the respective model type
@Templated
public class UserView extends Composite implements HasModel<User> {
  // ...

  @Override
  public void setModel(User model) {
    binder.setModel(model);
  }

  @Override
  public User getModel() {
    return binder.getModel();
  }
}
@Inject
ListWidget<User, UserView> userList;
List<User> models = userList.getValue();
// All of these will affect the list of displayed widgets
models.add(new User());
models.get(0).setUsername("John");
models.remove(0);

Todo List Example

Demo time

  • A simple todo-list that supports adding and completing items
  • Item models consist of descriptions and boolean for status

Todo List Example

How does it work?

  • Has a @Bindable model class — a Java bean with  description and  done properties
  • @Templated widget for a single list item
  • @Templated widget for the whole list

Dynamic Runtime Modules

Goals

  • We want to break up large projects into modules that don't need to be compiled together
  • Also gives flexibility for deployment at runtime

Dynamic Runtime Modules

JsInterop

  • Normally method names from Java source are obfuscated
  • JsInterop can preserve specific method symbols
  • This provides an interface for code outside a GWT-compiled script to call in

Dynamic Runtime Modules

@JsType

  • The @JsType annotation preserves all method names on a type
package org.errai.example;

@JsType
public class User {
  private String username;

  public void getUsername() {
    return username;
  }

  public void setUsername(String username) {
    this.username = username;
  }
}
var user = new org.errai.example.User();
user.setUsername("Max");
// Returns "Max"
user.getUsername();

Dynamic Runtime Modules

How Errai uses JsInterop

  • Use JsInterop to extend Errai's CDI features between GWT-compiled scripts
  • Allow injecting a @JsType from one script into another
  • Allow observing @JsType CDI events from one script in another

Dynamic Runtime Modules

Sharing an implementation

  • Imagine two GWT projects: consumer and producer
  • Both are compiled with this interface
  • But producer also contains an implementation

public interface MySimpleService {
  void doTheThing();
}

public class MySimpleServiceImpl implements MySimpleService {
  @Override
  public void doTheThing() {
    // ...
  }
}
public static native MySimpleService createService()/*-{
  return new producer.MySimpleServiceImpl();
}-*/;

Dynamic Runtime Modules

How do I share?

@JsType
public interface MySimpleService {
  void doTheThing();
}
@JsType
public class MySimpleServiceImpl implements MySimpleService {
  @Override
  public void doTheThing() {
    // ...
  }
}

Dynamic Runtime Modules

Consumer usage

  • Errai IoC will detect that MySimpleService is a @JsType
  • Will assume that an implementation is available at runtime
  • At runtime, will look for an implementation in the window context
public class ConsumingBean {
  @Inject
  MySimpleService service;
}

Dynamic Runtime Modules

Producer usage

  • No extra code needed! When a @JsType concrete class is found, it is automatically added to the window context

Dynamic Runtime Modules

How could I use this?

  • Structure application into separate runtime modules that export JsInterop services
  • Javascript implementations of @JsType interfaces can also injected

Summary

What can Errai do for you?

  • Provides declarative dependency injection
  • Provides declarative features for MVP style UI code
  • Supports a declarative way of publishing events and services across script boundaries via JsInterop

Thanks for listening!

An Introduction to Errai 4.0 -- GWT Con 2015

By Max Barkley

An Introduction to Errai 4.0 -- GWT Con 2015

The roadmap for the next major release of Errai.

  • 1,461
Loading comments...

More from Max Barkley