21
I Use This!
Activity Not Available

News

Posted over 12 years ago by [email protected] (Jonathan Fuerth)
Throughout our summertime communications blackout (sorry about that), the Errai team has been working overtime to further polish and stabilize all the great features in Errai 2.0 while also introducing a bunch of brand new features. This article ... [More] outlines all the major changes between Errai 2.0 and Errai 2.1.If you are new to Errai, the quickest way to get started is via the archetypes described in our quickstart guide.New in 2.1We're calling these new features in 2.1 "preview" because we want a chance to incorporate your feedback before we lock down the APIs in 3.0. We crave your input: share your use cases, feature requests, and of course pull requests.Client-Side JPAErrai 2.1 adds JPA2 to our Java-EE-6-in-the-client lineup. Errai JPA implements a subset of JPA 2.0, allowing familiar JPA code to do double-duty on the client and the server. For example, the following familiar-looking JPA entity can be persisted the in the browser's local storage:@NamedQueries ({  @NamedQuery(name="allAlbums",              query="SELECT a FROM Album a ORDER BY a.releaseDate, a.artist"),  @NamedQuery(name="albumByName",              query="SELECT a FROM Album a WHERE a.name LIKE :name")})@Entitypublic class Album {  @GeneratedValue  @Id  private Long id;  private String name;  @ManyToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE})  private Artist artist;  private Date releaseDate;  private Format format;  public Long getId() { return id; }  public void setId(Long id) { this.id = id; }  ...  @Override  public String toString() {    return "Album [id=" id ", name=" name            ", artist=" (artist == null ? "null" : artist.getName())            ", format=" format            ", releaseDate=" releaseDate "]";  }}Of course, this code does the same thing on the client as it would on the server:@Inject EntityManager em;public void createExampleAlbum() {  Artist samNDave = new Artist();  samNDave.setName("Sam & Dave");  samNDave.addGenre(new Genre("Rock"));  samNDave.addGenre(new Genre("Soul"));  samNDave.addGenre(new Genre("R&B"));  Album album = new Album();  album.setArtist(samNDave);  album.setFormat(Format.LP);  album.setName("Hold On, I'm Comin'");  album.setReleaseDate(new Date(-121114800000L));  em.persist(album);  em.flush();}public List<Album> fetchAlbums(String nameContains) {  TypedQuery<Album> query = em.createNamedQuery("albumByName", Album.class);  query.setParameter("name", "%" nameContains "%");  return query.getResultList();}Get your hands dirty by playing with the demo, which you can find on GitHub.ErraiUI TemplatesAs we clarified previously, GWT offers a wide array of choices when it comes to implementing your user interface. You can opt for declarative XML-based layout with UIBinder, programmatic layout with GWT panels and widgets, or even mash up GWT with something else like jQuery.In Errai 2.1, we're adding a new option to the mix: Errai UI. Errai UI gives you declarative layout through templates that are valid HTML 5 documents, paired with Java classes that imbue behaviour into them. Of course, you get compile-time checks to make sure everything lines up properly. We want to help you avoid unpleasant surprises at runtime!Here's an Errai UI template:<!DOCTYPE html><div>  <label for=itemName>Name:</label>  <input id=itemName type=text data-field=name>  <br>  <label for=itemDept>Department:</label>  <input id=itemDept type=text data-field=department>  <br>  <label for=itemComments>Notes:</label>  <input id=itemComments type=text data-field=comment>  <br>  <button class=btn data-field=saveButton>Save</button></div>The only special bits are the data-field attributes. These line up with field names in the companion Java class, like this:@Templatedpublic class ItemForm extends Composite {  @Inject @DataField private TextBox name;  @Inject @DataField private TextBox comment;  @Inject @DataField private TextBox department;  @Inject @DataField private Button saveButton;  public void grabKeyboardFocus() {    name.setFocus(true);  }  @EventHandler("saveButton")  public void onSaveButtonClicked(ClickEvent event) {    // this method will be called for each click event on saveButton  }}Each @DataField field is matched up with the corresponding element in the template, and a reference to it is injected. If you prefer, you can also declare fields as raw DOM element types rather than GWT widgets (for example, the name field could have been an InputElement rather than a TextBox). And you're not limited to just the standard DOM elements plus the widgets that come with GWT. You can inject your own widget types, even (especially?) other ErraiUI @Templated ones.To handle events, simply annotate a method with @EventHandler("DataFieldName"). The method should take an argument of the event type you want to receive. Errai UI will ensure the source node sinks the appropriate events, and it will deliver them to your method each time they happen.To learn more, check out the ErraiUI demo, and also read through Errai UI's reference guide.But wait! There's more!There are two more new Errai modules that go great with Errai UI: data binding and navigation.Model-View Data BindingErrai Data Binding is a great complement to Errai UI, but it's also just as handy in conjunction with other approaches to UI that you may already be using in your GWT and Errai apps.Errai Data Binding lets you bind property values in your model objects to widgets in your UI.To make a model object amenable to having its properties bound, annotate it with @Bindable:@Bindablepublic class Employee {  private int id;  private String name;  private Integer age;  private boolean active;  public int getId() { return id; }  public void setId(int id) { this.id = id; }  public String getName() { return name; }  public void setName(String name) { this.name = name; }  public Integer getAge() { return age; }  public void setAge(Integer age) { this.age = age; }  public boolean isActive() { return active; }  public void setActive(boolean active) { this.active = active; }}Then to establish data bindings to UI widgets, use the fluent configuration API:public class EmployeeForm {  private final TextBox nameTextBox = new TextBox();  private final TextBox ageTextBox = new TextBox();  private final CheckBox activeCheckBox = new CheckBox();  private Employee employee;  @PostConstruct  public void init() {    employee = DataBinder.forType(Employee.class)      .bind(nameTextBox, "name")      .bind(ageTextBox, "age")      .bind(activeCheckBox, "active")      .getModel();  }}The model instance that comes back from the getModel() call is now automatically kept in sync with the bound UI fields.Declarative Data BindingWhen Errai Data Binding is used together with Errai UI templates, you can skip the fluent API and simply declare "auto-bindings." Going back to the ItemForm example:  ...  @Inject @AutoBound private DataBinder<Item> itemBinder;  @Inject @Bound @DataField private TextBox name;  @Inject @Bound @DataField private TextBox comment;  ...By injecting an @AutoBound DataBinder and adding the @Bound annotations on the widgets, we get a declarative approach to data binding. With the above code snippet in place, it will always be true that itemBinder.getModel().getName().equals(name.getText()).Errai data binding also allows custom converters, wrapping existing model objects, and more. See the reference guide for all the juicy details!"Multi-Page" NavigationThe third new UI-related feature in 2.1 is Errai Navigation. Errai Navigation adds a decentralized, declarative configuration mechanism to GWT's built-in History facility. This allows back-button and forward-button navigation, plus bookmarkable locations within your app. And since the configuration is declarative, it even produces navigation flow graphs like this at compile time:The navigation system simply manages the contents of a panel (a div element in the DOM): based on what comes after the # in the location bar, the contents of that div change. Typically, in your app's entry point, you would add that panel to a large, central region of the document. Headers, footers, and sidebars can remain outside of this div, which allows them to stay in place when the user navigates between pages.As an example, if you want the URL http://example/my-app/host-page.html#FunPage to cause the page body to contain an instance of your FunPage widget, you would do the following:@Pagepublic class FunPage extends Widget {  // whatever Widgety things you want to do}Pages are CDI beans, and the navigation obtains instances from the client-side bean manager when needed. So the above implicit-scoped bean would be newly instantiated each time the browser's URL bar changes to http://example/my-app/host-page.html#FunPage. If you'd prefer one instance of FunPage to hang around for the life of the app (simply appearing and disappearing based on the current URL fragment,) just annotate it with @ApplicationScoped.But what good are pages without links between them? To make links between pages, inject TransitionTo instances like so:@Pagepublic class FunPage extends Widget {  @Inject TransitionTo<UltraFunPage> upgradeLink;  @Inject TransitionTo<WelcomePage> quitLink;  @Inject TransitionTo<SillyPage> sillinessEnsues;  public void onQuitButtonClick(ClickEvent e) {    quitLink.go();  }  // whatever Widgety things you want to do}To follow a link, simply call go() on the link in question.These links make up the arrows in the navigation graph that's produced at compile time. The type parameter controls the widget (CDI bean) type that provides the page contents, and the field names are the label text on the arrows.Of course it goes without saying that Errai Navigation goes great with Errai UI templates: a @Templated widget can also be a @Page.Improved Since 2.0That was a lot of new API, but we didn't stop there. We've also made a bunch of incremental improvements to the existing APIs from 2.0 and earlier.Client-side Remote Call Interceptors (JAX-RS and RPC)Sometimes you need a chance to tweak a request just before it's sent to the server. For example, maybe you need to add special authentication headers to certain REST requests. Or maybe you want to short-circuit requests when you already have locally-cached data. Previously, you would have had to give up on the typesafe Errai JAX-RS Caller<T> interface for those requests, and fall back to RequestBuilder.Well, starting in Errai 2.1, you can intercept, inspect, modify, and even cancel any Errai JAX-RS and Errai RPC request. See the documentation for the details and example code.GWT 2.5 CompatibilityErrai 2.1 still defaults to GWT 2.4, but we've tested it with the release candidates of GWT 2.5, and we're committed to compatibility. You're free to choose whichever you're most comfortable with.In Errai 3.0, we do plan to bump up the minimum requirement to GWT 2.5, so get testing!Code-and-Refresh: Better Than EverCode-and-refresh support (Dev Mode) is crucial to a pleasant GWT development experience. We're pleased to say that Errai's code-and-refresh support for CDI is now better than ever. You can make almost any change–even structural changes–to your client-side code, refresh in the browser, and see the results right away.Additionally, the dynamic (server-side) marshalling system in Errai 2.1 is now run through the same set of tests as the statically-compiled marshallers. This means you can stick to dynamic marshalling at development time, with two big advantages: firstly, it makes dev mode setup simpler (especially when using an external web server); secondly, it behaves well in conjunction with server-side hot reload products such as JRebel.Errai Marshalling: Now Compatible with JacksonSpeaking of Marshalling enhancements, Errai 2.1 now offers compatibility with the popular Jackson Java-JSON marshalling package. Via the use of a converter, Errai JAX-RS clients can produce requests in a Jackson-compatible format, and can also understand and properly demarshal Jackson payloads in the response. The major use case is that you can now call many pre-existing JAX-RS resource methods from an Errai JAX-RS client. Another possibility is to use Jackson compatibility mode in a new Errai JAX-RS app in order to provide simpler JSON payloads to non-Errai clients. There are a few weaknesses compared with Errai's fully-typed native JSON format, but you can do pretty much everything in Errai's Jackson compatibility mode that you can do with plain Jackson.The user guide has a section that details how to enable Jackson compatibility mode in the REST client.Try itNow that 2.1.0.RC2 is out in the wild, I hope you will take the time to test your Errai app with it. We hope to go final soon, so get those bug reports and pull requests in before it's too late!And if you're new to Errai, the quickest way to get started is via the archetypes described in our quickstart guide.Happy hacking! [Less]
Posted over 12 years ago by [email protected] (Christian Sadilek)
After an intense summer of coding on Errai 2.1, the whole Errai team will be on tour this fall presenting the latest and greatest in rich web development. We'll be covering our greatest hits and some exciting new material: Errai JPA, Errai UI, data ... [More] binding, page navigation and more!Here are the tour dates:Toronto: Sep. 18 at 7pm Mike Brock, Christian Sadilek and Jonathan Fuerth will be at the Toronto Google Developer Group meetup. Find all details here.Montreal: Sep. 25 at 5:30pmJonathan and Christian will present Errai at the Montreal Java User Group.San Francisco: JavaOne (Sep. 30 - Oct. 4)Oct. 2 at 11am: Christian and Jonathan will present "CDI in the browser. Wait? What!" at the JBoss mini theatre on the trade show floor.Oct. 3 at 11am: Lincoln Baxter will make all your wildest dreams come true with HTML5 and Errai UI at the JBoss mini theatre.Oct. 3 at 2pm: Jonathan and Christian will present "In-Browser Storage and JAX-RS Clients: Typesafe Edition" at the JBoss mini theatre.Oct. 4 at 12:30pm: Christian and Jonathan will present Errai in this full JavaOne conference session.Nice: Oct. 12 at 6pmMike Brock at the Riviera JUG! Yes, he will come all the way across the pond for just one day! Make sure to meet him there. More details here.We hope to meet many of you at these events! [Less]
Posted over 12 years ago by [email protected] (Mike Brock)
We at Red Hat are very pleased to announce our involvement in the new open source initiative for the Google Web Toolkit. Today at Google I/O, the new GWT steering community was announced and initially consists of the following people:Ray Cromwell ... [More] (Google)Darrel Meyer (Sencha)Mike Brock (Red Hat)Christian Goudreau (Arcbees)Joonas Lehtinen (Vaadin)Thomas BroyerStephan HabermanDaniel Kurka (mgwt)I am very excited to represent Red Hat's value, commitment to community and open source to help drive progress and innovation with GWT and beyond.Errai represents a major bet on the future of GWT for Red Hat, and this new initiative will allow us to double-down, by allowing us to contribute directly to the core of GWT, where the broader community can benefit from our collective investment.My thanks to Ray Cromwell, Google and the rest of the initial steering members for helping to bring this to fruition.Our steering mailing list is now open to the public, and I know I can't wait to get the discussion rolling. The best is yet to come for GWT!   [Less]
Posted almost 13 years ago by [email protected] (Jonathan Fuerth)
After months of lead-up, a few necessary breaking API changes, and a pile of feedback from our user community, the Errai Team is proud to announce the release of Errai 2.0.0.Final.In case you haven't heard, the Errai framework builds on the Google ... [More] Web Toolkit (GWT). We've previously covered what GWT is and what it is not. But how does Errai build on GWT?Errai eliminates the need for boilerplate code and configuration in several areas, including entry points, remote services, UiBinder, and more.Errai brings some of parts of Java EE 6 to the browser: CDI (standardized IoC and eventing) and a typesafe JAX-RS client. A JPA 2.0 implementation is on the way in 2.1!Errai includes a simpler-to-use and more flexible marshalling and RPC systemErrai provides a client-server message bus with bidirectional push messaging (much of the above is based on Errai's Bus, and you can choose to use the bus API directly in your code).Errai is guided by the belief not only that a uniform programming model across client and server is a big advantage, but that it's also advantageous to share significant parts of your code base between the client tier and the server tierFor the specifics, complete with code examples, be sure to check out our comprehensive walkthrough of the features in Errai 2.0 from back when we released 2.0.Beta1.ThanksOn behalf of the Errai team, I'd like to thank everyone who tried the Errai 2.0 snapshots, betas, and release candidates. We received tons of valuable feedback in the form of bug reports, feature requests, use cases we'd never have thought of ourselves, and even a few patches. Thanks to everyone who communicated their experiences with us. Errai 2.0 would not have been the same without you!Apologies to those who gave us some excellent feature requests that we didn't have time to implement before the 2.0 cutoff. We haven't forgotten you. And remember, we do gladly accept pull requests! :-)Thanks also the the JBoss Tools team, who worked closely with us throughout the 2.0 beta cycle to ensure the tooling was up to snuff. These guys enhanced the Eclipse WTP Maven configurator (m2e-wtp) to ensure Errai projects deploy cleanly from within Eclipse, and even created a new GWT Maven configurator that configures the Eclipse GWT Tooling based on the maven-gwt-plugin configuration. This is huge. Thanks, guys!Thanks also to Red Hat and JBoss for believing in the value of open source community projects, and giving us the latitude to shape Errai in the way our community sees fit. This is a great way to build software, and we're all proud to be participants in this way of doing business.The FutureAs we (finally!) cycle out of cleanup mode and back into R&D mode, we've already started on a number of exciting features for 2.1. Watch for blog posts on the following:Support for parts of JPA 2.0, plus a data synchronization system that takes the drudgery of data sync out of your project's codebase.A data binding module that eliminates even more boilerplate from the MVP pattern by enabling bidirectional property updates between model objects and UI components. This forms a solid foundation for some exciting UiBinder integration.A Jackson-compatible marshalling mode in Errai Marshalling when used with the JAX-RS client.Mobile support. We've already got a demo that shows how to turn HTML 5 DeviceOrientation events into CDI events (supports iOS/Chrome/Android 4.0); we plan to flesh this out into a broader-reaching mobile support module. Let us know what kind of mobile support you're looking for!Until next time,The Errai TeamMike BrockChristian SadilekJonathan Fuerth [Less]
Posted almost 13 years ago by [email protected] (Mike Brock)
In the last post, we got our feet a little bit wet by exploring the basics of Errai's dependency injection framework, which we call Errai IOC. In this post, we're going to continue the dive by taking a look at producers and bean ... [More] life-cycles.Statically wiring up your application is one thing. But what if you want to create managed beans dynamically at runtime? Or what if you want to control what beans get injected based on the runtime environment?Look no further.Dependent Scoped BeansOut of the box, Errai supports two basic scopes: the singleton scope, and the dependent scope. For the sake of consistency, CDI's @ApplicationScope is aliased to the singleton scope within the context of the client application.Most developers should be familiar with the concept of a singleton, and should easily come to understand what it's use on a bean implies; scoping a bean to a singleton scope will result in there being exactly one instance of that bean created during the lifecycle of the application. The dependent scope is a little bit different. It is a scope which is dependent on the scope, and by extension, the lifecycle of the bean which it is injected to. But it also has the property of producing a new instance of the bean for every different injection context.When it comes to developing UI applications in the browser around beans, this becomes a fairly important -- and natural -- way to accomplish component reuse.For example, we might wish to create an application component which is newly instantiated every time a user performs a certain action -- like a dialog box popping up.@Dependentpublic class MyDialogBox {  @Inject SomeBean bean;   @PostConstruct  private void init() {    // do stuff  }    public void show() {    // do stuff to show dialog box.  }  public void hide() {    // do stuff to hide dialog box.  }    @PreDestroy  private void destroyBean() {    hide();  }}So we create @Dependent scoped bean. Now, unlike the singleton scope, this bean will not be instantiated by the container unless it is injected into another bean, or it is explicitly created from an instance factory or the bean manager.Let's take a look at how we might go about that.@Singletonpublic class MySingletonBean() {  @Inject Instance<MyDialogBox> dialogBoxInstance;  // ... assume we've done some UiBinder stuff here ...   @UiHandler  void onOpenDialogClick(ClickHandler handler) {    MyDialogBox myDialogBox = dialogBoxInstance.get();      myDialogBox.show();  }}In this example we have injected an instance of javax.enterprise.inject.Instance parameterized with the bean type we'd like it to provide.  In this case, since MyDialogBox is dependent scoped, every single time dialogBoxInstance.get() is called, a new instance of the bean, fully wired will be created.And just as it's been created by the bean manager, it can also be destroyed by the bean manager. Resources that the bean obtains from the container, can automatically be de-allocated cleanly through explicitly garbaging the bean.Errai IOC actually provides it's own mechanism which is different from CDI for doing this, to make interaction with the BeanManager for ad-hoc disposal easier in client code. It is the org.jboss.errai.ioc.client.api.Disposer interface. It works pretty much the same as Instance, in that you inject it, parameterized with the bean it represents:@Singletonpublic class MySingletonBean() {  // .. //  @Inject Disposer<MyDialogBox> dialogBoxDisposer;   void closeDialogBox(MyDialogBox dialogBox) {    dialogBoxDisposer.dispose(dialogBox);  }}If you refer back to our implementation of MyDialogBox, you will notice that we have indicated a @PreDestroy method, which is to be called by the bean manager when the bean is destroyed.  In that case, we just had it call its own hide() method to make the point. But the effects of disposing of a bean are far more than just calling that method. Any other beans that were created as a result of constructing that bean will also be destroyed implicitly. And any observer methods, bus service endpoints, and such will automatically be deregistered. Thus, using the bean manager to create and destroy your beans, gives you the advantage of having a standard way to manage and dispose of resources as build out your application.ProducersThis is cool, but what happens when we want to dynamically choose what instances to return to created beans at runtime? Enter the producer.Producers produce beans. Could that be put more concisely? They essentially allow you to offload control of bean instance creation from the bean manager itself, into logic you so choose. Let's take a look at a basic example:@Singletonpublic class MyProducerBean() {  @Produces @Singleton  private NotificationHandler produceNotificationHandler() {    if (Browser.supportsWebkitNotification()) {      return new HTML5WebkitNotificationHandler();    }    else {      return new SimpleNotificationHandler();    }  }}This is a contrived example. Don't go looking for any class called Browser.  But contrived or not, it's probably the sort of thing you'd find yourself wanting to do in the world of web applications.Here, we've created a producer method by annotating it with the @javax.enterprise.inject.Produces annotation. But we've also annotated the method with the @Singleton annotation. This tells the container that it should call the method exactly once at runtime and cache the instance result in the bean manager, and return that same instance to all injection points. Not specifying a scope, implies the producer is dependent-scoped, as we talked about in our previous section.In this example, we are checking to see if our browser support WebKit desktop notifications. If it does, we return an instance of the HTML5WebkitNotificationHandler which implements the NotificationHandler interface and obviously knows how to produce desktop notifications. In the alternative, we return a SimpleNotificationHandler. Perhaps it provides window alerts. I'll let you speculate on what the fallback functionality is here.The bottom line is that other parts of the application which want to provide notifications now only need to @Inject NotificationHandler into their beans, providing a good separation of concerns.  The components need only refer to the interface without knowledge of the actual implementation. That's the power of the DI pattern.So that's the basics of producers.In the next installment of this series, we'll look at bean alternatives and qualifiers. [Less]
Posted almost 13 years ago by [email protected] (Mike Brock)
For those in Bangalore area, I'll be talking at GIDS 2012 this coming week. Which will be a great opportunity to come check out what we've been working on this past year.This talk comes on the heels of our last official beta release (beta4) before ... [More] our scheduled release candidate for 2.0 So I'm pretty excited to show people what's been cooking.If there's people in the Bangalore area who can't make GIDS but are interested in Errai, by all means ping me here on the blog and we'll see if we can arrange a meet-up.I'm also excited to continue my blog series on CDI in the Browser -- which I will do, as soon as I make landfall back home in a week or so. Stay tuned. [Less]
Posted almost 13 years ago by [email protected] (Mike Brock)
A central facet of the Errai programming model is the use of dependency injection (DI). The preferred programming model is a subset of the JSR-299 Context and Dependency Injection specification.This is not the only DI solution for GWT. Gin is clearly ... [More] the popular choice among GWT developers. But there are a few reasons you might want to consider looking into Errai as a good choice for doing dependency injection in your client code.As we have gravitated towards standardizing around CDI, we have thus moved towards more container-oriented applications. Whereas, the Gin/Guice model aims to do absolutely no magic, we aim to at least give you a sprinkle of fairy dust to help eliminate boilerplate and help make your application more modular.The first evidence of just a little bit of fairy dust occurs when you create your first GWT EntryPoint in Errai.@EntryPointpublic class MyErraiEntryPoint {   // class body here.}This is a little bit different than you may be used to with a GWT project -- instead of actually implementing the GWT EntryPoint interface, we have annotated a normal bean as our entry point bean.The only thing that was necessary to accomplish this, was to have Errai IOC added as a module in our GWT project.The cool thing is, MyErraiEntryPoint is a fully managed bean. We can inject other beans into it, and we can do lifecycle events like @PostConstruct on it.  Let's update our example:@EntryPointpublic class MyErraiEntryPoint {  @PostConstruct  public void sayHello() {    Window.alert("Hello, there!");  }}We added an arbitrarily named method sayHello() to our class and added a @PostConstruct annotation.@PostConstruct is a standard lifecycle annotation which is part of the javax.annotation.* package. It is supported in EJBs, CDI Beans, and by Errai IOC, naturally.  Its contract guarantees that the container will call the method before the bean is put into production, and only after all dependency injection tasks have been satisfied.Thus, it provides a good way of doing things that need to be done at the startup of your application after the container has wired all the beans.Errai goes a little bit further, building on the @PostConstruct idea, and adding a similar but distinct lifecycle annotation known as @AfterInitialization, for which there is no real analogue in CDI proper. In the case of @AfterInitialization calls, the method is guaranteed to be called only after all framework extensions (the message bus, RPC services, etc) have entered a ready state.It turns out this is necessary, since the asynchronous nature of JavaScript in the browser means that your application will almost always finish wiring itself up before fancy things like WebSockets have been negotiated and are ready to start receiving messages.So if right out of the gate we need to talk to the server, we can modify our bean again:@EntryPointpublic class MyErraiEntryPoint {  @Inject MessageBus bus;   @AfterInitialization  public void sayHelloToServer() {    MessageBuilder.createMessage()      .toSubject("ServerService")      .command("SayHello")      .done().sendNowWith(bus);  }}So we've built an entire application that loads, and the first thing that happens is it sends a message to the server over the ErraiBus. That doesn't seem like much. But the only boilerplate code we've written are annotations.This nice, concise, programming model is all made possible by the use of dependency injection and all the services built around the container.But this is just scratching the surface. In the next part of this series we'll explore working with producers and dependent scoped beans! [Less]
Posted almost 13 years ago by [email protected] (Jonathan Fuerth)
My previous post was about the Errai Marshalling framework and its facilities for working with immutable types. In that post, I laid out how to use Errai's @MapsTo annotation to create entity instances via a public constructor or—as is often ... [More] advantageous—a public static factory method.But as an entity class grows to accommodate a real-world-use-case, a third approach to creating instances of immutable types becomes more and more appealing: the builder pattern.If you use the builder pattern exactly as laid out by Joshua Bloch, Errai's marshalling system will be unable to infer a property mapping for the entity's constructor:import java.util.Date;import org.jboss.errai.common.client.api.annotations.Portable;@Portablepublic final class OrientationSensorReading {  private final Date observationTime;  private final double x;  private final double y;  private final double z;  // ERROR: Errai Marshalling does not know what to do with this constructor  private OrientationSensorReading(Builder builder) {    this.observationTime = new Date(builder.observationTime.getTime());    this.x = builder.x;    this.y = builder.y;    this.z = builder.z;  }  public Date getObservationTime() { return new Date(observationTime.getTime()); }  public double getX() { return x; }  public double getY() { return y; }  public double getZ() { return z; }  public static class Builder {    private Date observationTime = new Date();    private double x;    private double y;    private double z;    public Builder time(Date time) { this.observationTime = time; return this; }    public Builder x(double x) { this.x = x; return this; }    public Builder y(double y) { this.y = y; return this; }    public Builder z(double z) { this.z = z; return this; }    public OrientationSensorReading build() {      return new OrientationSensorReading(this);    }  }}You could work around this issue by implementing a custom marshaller (these are explained in in the Errai reference guide). But that's a burden: it's extra, external code you have to revisit every time you add or remove a property on your entity type.A better approach is to adopt a modified version of Bloch's builder pattern. Instead of giving the class a constructor that takes the Builder as its sole parameter, create one big constructor that takes every single property, each of which annotated with a @MapsTo annotation. This constructor does triple duty as the target of Builder.build(), the target of Errai's de-marshaller, and a place to hang directions for Errai's marshaller generator. Now you have the builder pattern, and you haven't given up the convenience of Errai's automatic marshaller generation:import java.util.Date;import org.jboss.errai.common.client.api.annotations.Portable;import org.jboss.errai.marshalling.client.api.annotations.MapsTo;@Portablepublic final class OrientationSensorReading {  private final Date observationTime;  private final double x;  private final double y;  private final double z;  public OrientationSensorReading(      @MapsTo("observationTime") Date observationTime,      @MapsTo("x") double x,      @MapsTo("y") double y,      @MapsTo("z") double z) {    this.observationTime = new Date(observationTime.getTime());    this.x = x;    this.y = y;    this.z = z;  }  public Date getObservationTime() { return new Date(observationTime.getTime()); }  public double getX() { return x; }  public double getY() { return y; }  public double getZ() { return z; }  public static class Builder {    private Date observationTime = new Date();    private double x;    private double y;    private double z;    public Builder time(Date time) { this.observationTime = time; return this; }    public Builder x(double x) { this.x = x; return this; }    public Builder y(double y) { this.y = y; return this; }    public Builder z(double z) { this.z = z; return this; }    public OrientationSensorReading build() {      return new OrientationSensorReading(observationTime, x, y, z);    }  }}Yes, it's a little bit more verbose than Bloch's approach. But the client code using the builder is identical, and the integrity of the immutable type is in no way compromised. And it's still all in the same file, and far less verbose than a handwritten custom marshaller.Future WorkThere's always room for improvement. In particular, I'd like the option of making the entity constructor (the one with the @MapsTo annotations) package private. This would enforce usage of the builder, which is less error prone than the constructor. That's why you went to the trouble of creating a builder in the first place, right? This is in our issue tracker as ERRAI-234.Additionally, the contract of Errai's @Portable annotation is that all nested classes of a @Portable class are also portable. This means Errai will generate marshallers for your Builder subclasses. Although this is harmless in the above examples, it becomes a problem when your builders have mandatory fields expressed as constructor parameters. We're tracking this issue as ERRAI-233. The workaround for now is to include a public no-args constructor in any such Builders. [Less]
Posted almost 13 years ago by [email protected] (Christian Sadilek)
Development teams collaborating on the same codebase are always faced with the challenge of keeping their source code maintainable as it evolves and grows over time. By choosing GWT to implement your web application you already gain the benefit of ... [More] having IDE support for client-side code refactorings. This is a distinct advantage, but how should a GWT application be designed to allow for the collaboration of large teams and stay maintainable over the course of time?The Model-View-Presenter (MVP) pattern provides an answer to this. Applying the MVP pattern in GWT applications is described in this two-part article: Large scale application development and MVPIn this post, I will demonstrate a modified version of the example code of this article series to show how Errai makes implementing a MVP application in GWT even easier and how Errai helps to further decouple the individual components. The source code of the modified example can be found on GitHub: https://github.com/csadilek/errai-mvp-demoSo, let's take a look at the individual components used in MVP and the modifications and improvements made to it using Errai.The ModelThe business objects used in this example (Contact and ContactDetail) remain more or less unchanged. The @Portable annotation was added to mark them as serializable by Errai. Errai marshalling was designed for maximum flexibility and to impose as few limitations to serializable classes as possible (see our documentation for details). The classes do not need to (but may of course) implement java.io.Serializable.The ViewThe views contain only UI layout code. They have no knowledge of the model, other views, transitions and contain no application logic. Errai can improve view implementations by providing the ability to inject UiBinders. Without Errai:public class EditContactView extends Composite implements EditContactPresenter.Display {    interface EditContactViewUiBinder extends UiBinder<Panel, EditContactView> {}  private static EditContactViewUiBinder uiBinder =        GWT.create(EditContactViewUiBinder.class);  ...}With Errai:public class EditContactView extends Composite implements EditContactPresenter.Display {  @Inject   UiBinder<Panel, EditContactView> uiBinder;  ...}The PresenterThe presenters contain all the application logic: view transitions, RPCs, etc.In the original example, the RPC proxies, the event bus and the view instances are passed to the presenters as constructor arguments. Using Errai, we can now inject all these components.@Dependentpublic class EditContactPresenter implements Presenter {  public interface Display {    ...  }  @Inject  private Caller<ContactsService> contactsService;  @Inject  private HandlerManager eventBus;  @Inject  private Display display;  ...}This might seem like a minor improvement at first, but once your application grows this will become more than handy. Let's say you come to a point where all your presenters need an additional RPC proxy. Without dependency injection, you would have to change all constructors and all call sites!The GWT/RPC proxy was replaced with an Errai RPC proxy (the injected Caller). Errai RPC does not require an asynchronous interface nor a servlet based service implementation on the server. It can even be used to invoke methods on a server-side CDI bean (see our documentation for details).The Application ControllerThe application controller handles logic that is not specific to any presenter and also deals with history management and view transitions. It needs access to the event bus (which again we can inject using Errai IOC) to react on application events that trigger view transitions.@ApplicationScopedpublic class AppController implements Presenter, ValueChangeHandler<String> {  @Inject  private HandlerManager eventBus;    @Inject  private IOCBeanManager manager;  ...}It also needs to be able to create new presenter instances when the browser's history stack changes. To create new managed instances of presenters, we use Errai's client-side bean manager that will make sure all the injection points of presenters are satisfied and the instance is ready to use.public void onValueChange(ValueChangeEvent<String> event) {    String token = event.getValue();    if (token != null) {      Presenter presenter = null;      if (token.equals("list")) {        IOCBeanDef<ContactsPresenter> bean = manager.lookupBean(ContactsPresenter.class);        if (bean != null) {          presenter = bean.getInstance();        }      } else if (token.equals("add") || token.equals("edit")) {        IOCBeanDef<EditContactPresenter> bean =             manager.lookupBean(EditContactPresenter.class);        if (bean != null) {          presenter = bean.getInstance();        }      }      if (presenter != null) {        presenter.go(container);      }    }  }The EntryPointSince Errai allows us to use dependency injection for all the required components, the main difference here is that we no longer have to pass the RPC proxies and the event bus instance to the app controller which in turn would have to forward it to the presenters and views.The @Produces method provides the event bus instance to all the event bus injection points in all the presenters. The application controller itself is also just injected and started as soon as the app is finished initializing (@AfterInitialization).@EntryPointpublic class Contacts {  private HandlerManager eventBus = new HandlerManager(null);  @Inject  private AppController appController;  @AfterInitialization  public void startApp() {    appController.go(RootPanel.get());  }  @Produces  private HandlerManager produceEventBus() {    return eventBus;  }}So to sum it up, Errai's IOC container helps implementing the MVP pattern by further decoupling the individual components and by alleviating boilerplate code for UiBinders and RPC proxies.Future Work An extension that we are currently working on is the @MockFor annotation that can be used to replace an injected type with a mocked type for unit testing. During tests, a presenter could then get the mocked view injected in place for the actual view for example. The presenters can then be tested using a plain JUnit test instead of an integration test.@MockFor(EditContactsView.class) public class EditContactsMockView {   ...}As always, feedback is welcome and appreciated! [Less]
Posted almost 13 years ago by [email protected] (Mike Brock)
Dovetailing off the last post on marshalling, lovingly laid out by Jonathan, I'd like to talk about dealing with edge cases in Errai 2.0's marshalling framework.The real question is: what do you do when the annotations are not enough? What if I have ... [More] to marshal a legacy class that isn't very bean-like.Well, it turns out, we ran into these problems ourselves when implementing the default JRE marshallers. There are some classes which don't exactly lend themselves to just being slurped up into a reflection analyzer and having marshalling code emitted. And even if they did, they'd create very inefficient marshallers.There are a grand total of two ways to deal with this problem when you come to it. The first solution is to try and manually describe the model to Errai. The second solution is just to write your own marshaller by hand. Let's look at the former approach today!Teaching Errai about Your ModelThis approach has the advantage of not requiring that you manually deal with building up and parsing wire protocol stuff. Instead, we give Errai a picture of what it should do to build the object through a series of mapping instructions.A perfect example is the java.lang.Throwable class. Marshalling this class provides a few special challenges. For instance, to construct it with a message we must do so in a constructor argument. To chain a cause to it, we must call initCause(), and so on. Thus, Errai Marshalling's class analyzer is not going to do a very good job at comprehending the class. Instead, we will implement a MappingDefinition to describe the mappings needed to build and deconstruct a Throwable.The first thing we do is create a class which extends org.jboss.errai.marshalling.rebind.api.model.MappingDefinition. This is a base class which contains the model of the mapping.@CustomMappingpublic class ThrowableDefinition extends MappingDefinition {  public ThrowableDefinition() {    super(Throwable.class);    SimpleConstructorMapping constructorMapping = new SimpleConstructorMapping();    constructorMapping.mapParmToIndex("message", 0, String.class);    setInstantiationMapping(constructorMapping);    addMemberMapping(new WriteMapping("cause", Throwable.class, "initCause"));    addMemberMapping(new AccessorMapping("stackTrace", StackTraceElement[].class, "setStackTrace", "getStackTrace"));    addMemberMapping(new ReadMapping("message", String.class, "getMessage"));    addMemberMapping(new ReadMapping("cause", Throwable.class, "getCause"));  }}Let's go through this line-by-line to see what's going on here.super(Throwable.class);We call the super constructor, passing the the class reference for Throwable. This configures the MappingDefinition to associate your mappings with this class.SimpleConstructorMapping constructorMapping = new SimpleConstructorMapping();We instantiate a org.jboss.errai.marshalling.rebind.api.model.impl.SimpleConstructorMapping to represent the constructor that will need to be called to instantiate the Throwable.constructorMapping.mapParmToIndex("message", 0, String.class);We map the message field of the class to the first argument (index: 0) of the constructor, and specify that is of type java.lang.String.setInstantiationMapping(constructorMapping);We call MappingDefinition.setInstantiationMapping() (it's in the super class), to record that this constructor mapping is needed to instantiate the class.addMemberMapping(new WriteMapping("cause", Throwable.class, "initCause"));We add a member mapping for the cause field of Throwable. In this case we specify a WriteMapping, which implies a method which accepts exactly one argument. In this case, another Throwable. The method we want is initCause.addMemberMapping(new AccessorMapping("stackTrace", StackTraceElement[].class, "setStackTrace", "getStackTrace"));For the stackTrace field, we utilize the AccessorMapping, which is a convenient two-way mapping where we have symmetric getters and setters. In this case, setStackTrace() and getStackTrace().addMemberMapping(new ReadMapping("message", String.class, "getMessage"));This time we specify a ReadMapping. Which like its namesake, tells the marshalling framework how to read a field. In this particular case, we map the message field, to the getMessage method. The ReadMapping expects the method to return the specific type (in this case String), and accept exactly zero arguments.addMemberMapping(new ReadMapping("cause", Throwable.class, "getCause"));Like with message, we do the same for cause. And guess what? We've told Errai everything it needs to know about marshalling this class. In fact, since many other classes extend Throwable and have the exact same marshalling characteristics, we can place an additional annotation on our class to make this definition project across these types as well!@InheritedMappings(IOException.class, IllegalArgumentException.class, /* and more...  */))The use of the InheritedMappings annotation accomplishes the aliasing for us. And that's that! We've described to Errai how to marshal and demarshal Throwable class, and classes which inherit it!The next in this series will look at writing your own custom marshaller from scratch.Mike, out. [Less]