KEMBAR78
JavaCro'15 - GWT integration with Vaadin - Peter Lehto | PDF
GWT integration
with Vaadin
Peter Lehto
@peter_lehto
expert & trainer
Vaadin
&
GWT
GWT
Transport
mechanisms
QA
Vaadin
Connectors
Web
components
with
Polymer
Vaadin
&
GWT
Server driven UI
framework with GWT
based thin client
UI
Browser
UI
Browser
Widgets
Theme
UI
Browser
Widgets
Theme
UI
Browser
Backend
Server
Widgets
Theme
UI
Browser
Backend
Server
Widgets
Service (GWT-RPC)
Backend
Server
UI Backend
Server
Browser
UI Backend
Server
Widgets Components
Theme
Browser
UI Backend
Server
Widgets Components
Theme
Browser
UI Backend
Server
Widgets Components
User Interface
Components
Developer
Productivity
Rich
UX
Vaadin += GWT
GWT
Transport
mechanisms
RequestBuilder
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
try {
builder.sendRequest(requestDataString, new RequestCallback() {
@Override
public void onResponseReceived(Request request, Response response) {
int statusCode = response.getStatusCode();
String text = response.getText();
}
@Override
public void onError(Request request, Throwable exception) {
// TODO Handle asynchronous problems
} });
} catch (RequestException e) {
// TODO Handle synchronous problems
}
RequestBuilder
Good
• It just works
RequestBuilder
Good
• It just works
Bad
• Very low level
What to send?
Contact
public class Contact {
private String name;
private int yearOfBirth;
private List<String> emailAddresses;
private Address address;
public static class Address {
private String street;
private String city;
}
// + Getters and setters
}
String conversion
String data = contact.getName();
data += "," + contact.getYearOfBirth();
String[] parts = data.split(",");
contact.setName(parts[0]);
contact.setYearOfBirth(Integer.parseInt(parts[1]));
String conversion
String data = contact.getName();
data += "," + contact.getYearOfBirth();
String[] parts = data.split(",");
contact.setName(parts[0]);
contact.setYearOfBirth(Integer.parseInt(parts[1]));
JSON
{
name: "John Doe",
yearOfBirth: 1900,
address: {
street: "Happy Street 1",
city: "Turku"
},
emailAddresses: ["john@doe.com", "johndoe@gmail.com"]
}
JSONValue parsing
JSONObject json = JSONParser.parseStrict(string).isObject();
contact.setName(json.get("name").isString().stringValue());
contact.setYearOfBirth(
(int) json.get("yearOfBirth").isNumber().doubleValue());
contact.setAddress(
parseAddress(json.get("address").isObject()));
JSONArray emailAddresses =
json.get("emailAddresses").isArray();
for (int i = 0; i < emailAddresses.size(); i++) {
contact.getEmailAddresses().add(
}
}
JSONValue
Good
• It’s standard
• Human readable
• Compact format
JSONValue
Good
• It’s standard
• Human readable
• Compact format
Bad
• Not completely
typesafe
• Boilerplate
• Client only
What about the server?
Jackson on the server
ObjectMapper mapper = new ObjectMapper();
try {
Contact contact = mapper.readValue(string, Contact.class);
} catch (VariousExceptions e) {
// Do something sensible
}
Jackson and GWT?
- gwt-jackson
gwt-jackson
public static interface ContactMapper extends
ObjectMapper<Contact> {}
public Contact parseContact(String jsonString) {
ContactMapper mapper = GWT.create(ContactMapper.class);
Contact contact = mapper.read(jsonString);
return contact;
}
Jackson
Good
• Minimal 

boiler plate
• Can share code

between server

and client
Bad
• Only creating

and reading

Strings
Where to send?
Remote procedure call
public interface ContactService extends RemoteService {
public void saveContact(Contact contact);
public List<Contact> getContacts();
}
public interface ContactServiceAsync {
public void saveContact(Contact contact,
AsyncCallback<Void> callback);
public void getContacts(AsyncCallback<List<Contact>>
}
GWT-RCP
Good
• Simple but

powerful 

concept
• Default solution
• Optimized
Bad
• Sending large

object graph
• Polymorphism

problems
Prefer JSON + REST?
- me too :)
REST
GET /contacts
DELETE /contacts/5
PUT /contacts { name: “John Doe”, ... }
JAX-RS
@Path("/contacts")
public interface ContactsService {
@GET
public List<Contact> listContacts();
@Path("/{id}")
@DELETE
public void deleteContact(@PathParam("id") int id);
@PUT
public void createContact(Contact contact);
}
Vaadin
Connectors
So how about Vaadin?
- Put server in charge!
State synchronization
public class ContactState extends SharedState {
public String name;
@DelegateToWidget
public int yearOfBirth;
}
@OnStateChange("name")
private void updateName() {
doSomethingWithTheName(getState().name);
}
RPC
public interface ContactRpc extends ServerRpc {
public void deleteContact(int id);
}
// Register RPC handler on the server
registerRpc(new ContactRpc() {
@Override
public void deleteContact(int id) {
ContactDAO.deleteById(id);
} });
// Send RPC from the client
public void sendDelete(int contactId) {
getRpcProxy(ContactRpc.class).deleteContact(contactId);
}
Server
Button
Browser
Server
VButton
Button
Browser
Server
VButton
ButtonConnector
Button
Browser
Server
VButton
ButtonConnector
SharedState
Button
SharedState
Browser
Server
SharedState
SharedState
Button
VButton
ButtonConnector
Browser
Server
SharedState
SharedState
RPC
RPC
Button
VButton
ButtonConnector
Browser
Server
SharedState
SharedState
RPC
RPC
Button
VButton
ButtonConnector
Browser
Server
SharedState
SharedState
RPC
RPC
Button
VButton
ButtonConnector
Browser
Server
Button
VButton
ButtonConnector
SharedState
SharedState
RPC
RPC
server
client
Component
Widget
Connector
RPC
State
ButtonConnector
@Connect(Button.class)
public class ButtonConnector extends AbstractComponentConnector
implements ClickHandler, FocusHandler {
public void init() {
getWidget().addClickHandler(this);
}
@OnStateChange({ "caption", "captionAsHtml" })
void setCaption() {
getWidget().setCaptionText(getState());
}
public void onClick(ClickEvent event) {
getRpcProxy(ButtonServerRpc.class).

click(buildDetails(event));
}
}
ButtonState
public class ButtonState extends AbstractComponentState {
…
public String caption;
public boolean disableOnClick;
public int tabIndex;
…
}
ButtonServerRPC
public interface ButtonServerRpc extends ServerRpc {
public void click(MouseEventDetails mouseEventDetails);
}
Server RPC implementation
public class Button extends AbstractComponent {
…
private ButtonServerRpc rpc = new ButtonServerRpc() {
public void click(MouseEventDetails details) {
fireClick(details);
}
…
}
Vaadin Connectors
Good
• Stateful server
• Websocket

support
• Integrated

JSON
Bad
• Stateful server
• Tied to

framework
Web
components
with
Polymer
Reuseable HTML
components!
Problem: Unique DOM tree
Solution: Shadow DOM
Encapsulation
What shadow DOM looks like?
How? With Polymer
polymer-project.org/
<v-grid>
Vaadin Grid Client Widget
Expose JavaScript API via
JsInterop from GWT 2.8
Use Shadow DOM and HTML
imports from Polymer
@JsNamespace(JS.VAADIN_JS_NAMESPACE)
@JsExport
@JsType
public class GridComponent…
…
private final Grid grid; // Grid widget
public JSColumn addColumn(JSColumn jsColumn, Object beforeColumnId) {
grid.addColumn
}
…
@JsType
public interface JSColumn {
@JsProperty
String getName();
@JsProperty
void setName(String s);
<link rel='import' href='vaadin-grid-import.html'>
<link rel='import' href='../bower_components/polymer/polymer.html'>
<link rel="stylesheet" href="vaadin-grid.css" shim-shadowdom>
<dom-module id="v-grid">
<template>
</template>
</dom-module>
<script>
var prototype = {
is: “v-grid",
properties: {
…
},
created: function() {
this._grid = new vaadin.GridComponent();
},
attached: function() {
this._grid.attached(this, Polymer.dom(this).querySelector(“table”),
Polymer.dom(this.root));
},
…
}
</script>
GridWidget (js)
GridComponent (js)
polymer.html
webcomponents.js
demo.html vaadin-grid.html
Lessons learned today
1. There are several ways of communicating

between GWT client and server
2. Vaadin Connectors use custom hybrid of JSON and
RequestBuilder wrapped to higher level SharedState and RPC
3. gwt-jackson with REST is very interesting option
4. Polymer allows browsers to support features needed for

for web components
Thank you!
Peter Lehto
@peter_lehto
expert & trainer

JavaCro'15 - GWT integration with Vaadin - Peter Lehto