comparing gwt transport mechanisms

45
Leif Åstrand Product Manager Comparing GWT Transport Mechanisms lördag 24 januari 15

Upload: lastrand

Post on 16-Jul-2015

7.235 views

Category:

Software


1 download

TRANSCRIPT

Leif ÅstrandProduct Manager

Comparing GWT Transport Mechanisms

lördag 24 januari 15

Transport

lördag 24 januari 15

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

lördag 24 januari 15

Good

• It just works

Bad

• Low level

RequestBuilder

lördag 24 januari 15

Real world usage

8 %lördag 24 januari 15

What to send?

lördag 24 januari 15

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

}

Contact

lördag 24 januari 15

String data = contact.getName();data += "," + contact.getYearOfBirth();

String[] parts = data.split(",");contact.setName(parts[0]);contact.setYearOfBirth(Integer.parseInt(parts[1]));

String conversion

lördag 24 januari 15

String data = contact.getName();data += "," + contact.getYearOfBirth();

String[] parts = data.split(",");contact.setName(parts[0]);contact.setYearOfBirth(Integer.parseInt(parts[1]));

String conversion

lördag 24 januari 15

{ name: "John Doe", yearOfBirth: 1900, address: { street: "Happy Street 1", city: "Turku" }, emailAddresses: ["[email protected]", "[email protected]"]}

JSON

lördag 24 januari 15

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(

emailAddresses.get(i).isString().stringValue()); }}

JSONValue parsing

lördag 24 januari 15

Good

• It’s standard• Human readable

format• Compact format

Bad

• Not completely typesafe

• Boilerplate• Client only

JSONValue

lördag 24 januari 15

What about the server?

lördag 24 januari 15

ObjectMapper mapper = new ObjectMapper();try { Contact contact = mapper.readValue(string, Contact.class);} catch (VariousExceptions e) { // Do something sensible}

Jackson on the server

lördag 24 januari 15

ReflectionCode generation

lördag 24 januari 15

public static interface ContactMapper extends ObjectMapper<Contact> {}

public Contact parseContact(String string) { ContactMapper mapper = GWT.create(ContactMapper.class); Contact contact = mapper.read(jsonString); return contact;}

gwt-jackson

lördag 24 januari 15

Good

• Minimal boiler plate• Can share code

between server and client

Bad

• Only creating and reading strings

Jackson

lördag 24 januari 15

Where to send?

lördag 24 januari 15

public interface ContactService { public void saveContact(Contact contact); public List<Contact> getContacts();}

Remote Procedure Call

lördag 24 januari 15

public interface ContactService { public AsyncResult<Void> saveContact(Contact contact); public AsyncResult<List<Contact>> getContacts();}

Asynchronous

public interface ContactServiceAsync { public void saveContact(Contact contact, AsyncCallback<Void> callback); public void getContacts(AsyncCallback<List<Contact>> callback);}

lördag 24 januari 15

Good

• Simple but powerful concept

• The default solution• Optimized format

Bad

• Sending the entire object graph

• Polymorphism can cause huge files

• Optimized format

GWT-RPC

lördag 24 januari 15

Most popular!

51 %lördag 24 januari 15

Where to send JSON?

lördag 24 januari 15

GET /contacts

DELETE /contacts/5

PUT /contacts { name: "John Doe", ... }

REST

lördag 24 januari 15

@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);}

JAX-RS

lördag 24 januari 15

@Path("/contacts")public interface ContactsService extends DirectRestService { // Same content}

ContactsService contactsService = GWT.create(ContactsService.class);

REST.withCallback(myContactListCallback).call(contactsService).listContacts();

resty-gwt

lördag 24 januari 15

Good

• Any server• Any client

Bad

• Some boilerplate

resty-gwt

lördag 24 januari 15

Real world usage

6 %lördag 24 januari 15

Wild ideas

lördag 24 januari 15

Send interfaces instead of objects

lördag 24 januari 15

public interface Contact { public void setName(String name); public String getName();

public void setYearOfBirth(int yearOfBirth); public int getYearOfBirth();

public void setAddress(Address address); public Address getAddress();

public void setEmailAddresses(List<String> addresses); public List<String> getEmailAddresses();}

Contact interface

lördag 24 januari 15

New possibilities

Send partial updates

Manage entity identity

Use instance methods for RPC

lördag 24 januari 15

Good

• Entities do not need to be GWT compatible

• Combines RPC and entity management

• Automatic request handling

Bad

• Complex setup• Heavy coupling with

the server

RequestFactory

lördag 24 januari 15

Define messageGenerate code

lördag 24 januari 15

message Contact { required string name = 1; required int32 yearOfBirth = 2; repeated string emailAddresses = 3; optional Address address = 4; }

Contact message

lördag 24 januari 15

Good

• Any language• Google's data

interchange format• Backwards

compatible

Bad

• Binary format• Not very widely

used

Protocol Buffers

lördag 24 januari 15

What if we put the server in control?

lördag 24 januari 15

lördag 24 januari 15

public class ContactState extends SharedState { public String name;

@DelegateToWidget public int yearOfBirth;}

@OnStateChange("name")private void updateName() { doSomethingWithTheName(getState().name);}

@Overrideprotected ContactState getState() { return (ContactState) super.getState();}

State synchronization

lördag 24 januari 15

public interface ContactRpc extends ServerRpc { public void deleteContact(int id);}

// Register RPC handler on the serverregisterRpc(new ContactRpc() { @Override public void deleteContact(int id) { ContactDAO.deleteById(id); }});

// Send RPC from the clientpublic void sendDelete(int contactId) { getRpcProxy(ContactRpc.class).deleteContact(contactId);}

RPC

lördag 24 januari 15

Good

• Stateful server• Server push

Bad

• Stateful server• Tied to the

framework

Vaadin Connectors

lördag 24 januari 15

What if we completely hide the transport?

lördag 24 januari 15

// Fire event@InjectEvent<Contact> contactEvent;

public void updateContact(Contact contact) { contactEvent.fire(contact);}

// Listen to eventpublic void contactUpdateObserver(@Observes Contact contact) { ContactDAO.updateContact(contact);}

CDI events

lördag 24 januari 15

Good

• Transparent communication

• Server push

Bad

• Transparent communication

• Tied to the framework

Errai Bus

lördag 24 januari 15

Questions?

Answers?

Please rate the talk at gwtcreate.com/agenda? [email protected]

lördag 24 januari 15