Advertisement
Advertisement

More Related Content

Advertisement

Comparing GWT Transport Mechanisms

  1. Leif Åstrand Product Manager Comparing GWT Transport Mechanisms lördag 24 januari 15
  2. Transport lördag 24 januari 15
  3. 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
  4. Good • It just works Bad • Low level RequestBuilder lördag 24 januari 15
  5. Real world usage 8 % lördag 24 januari 15
  6. What to send? lördag 24 januari 15
  7. 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
  8. 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
  9. 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
  10. { name: "John Doe", yearOfBirth: 1900, address: { street: "Happy Street 1", city: "Turku" }, emailAddresses: ["john@doe.com", "johndoe@gmail.com"] } JSON lördag 24 januari 15
  11. 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
  12. Good • It’s standard • Human readable format • Compact format Bad • Not completely typesafe • Boilerplate • Client only JSONValue lördag 24 januari 15
  13. What about the server? lördag 24 januari 15
  14. 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
  15. Reflection Code generation lördag 24 januari 15
  16. 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
  17. Good • Minimal boiler plate • Can share code between server and client Bad • Only creating and reading strings Jackson lördag 24 januari 15
  18. Where to send? lördag 24 januari 15
  19. public interface ContactService { public void saveContact(Contact contact); public List<Contact> getContacts(); } Remote Procedure Call lördag 24 januari 15
  20. 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
  21. 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
  22. Most popular! 51 % lördag 24 januari 15
  23. Where to send JSON? lördag 24 januari 15
  24. GET /contacts DELETE /contacts/5 PUT /contacts { name: "John Doe", ... } REST lördag 24 januari 15
  25. @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
  26. @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
  27. Good • Any server • Any client Bad • Some boilerplate resty-gwt lördag 24 januari 15
  28. Real world usage 6 % lördag 24 januari 15
  29. Wild ideas lördag 24 januari 15
  30. Send interfaces instead of objects lördag 24 januari 15
  31. 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
  32. New possibilities Send partial updates Manage entity identity Use instance methods for RPC lördag 24 januari 15
  33. 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
  34. Define message Generate code lördag 24 januari 15
  35. 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
  36. Good • Any language • Google's data interchange format • Backwards compatible Bad • Binary format • Not very widely used Protocol Buffers lördag 24 januari 15
  37. What if we put the server in control? lördag 24 januari 15
  38. lördag 24 januari 15
  39. public class ContactState extends SharedState { public String name; @DelegateToWidget public int yearOfBirth; } @OnStateChange("name") private void updateName() { doSomethingWithTheName(getState().name); } @Override protected ContactState getState() { return (ContactState) super.getState(); } State synchronization lördag 24 januari 15
  40. 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); } RPC lördag 24 januari 15
  41. Good • Stateful server • Server push Bad • Stateful server • Tied to the framework Vaadin Connectors lördag 24 januari 15
  42. What if we completely hide the transport? lördag 24 januari 15
  43. // Fire event @Inject Event<Contact> contactEvent; public void updateContact(Contact contact) { contactEvent.fire(contact); } // Listen to event public void contactUpdateObserver(@Observes Contact contact) { ContactDAO.updateContact(contact); } CDI events lördag 24 januari 15
  44. Good • Transparent communication • Server push Bad • Transparent communication • Tied to the framework Errai Bus lördag 24 januari 15
  45. Questions? Answers? Please rate the talk at gwtcreate.com/agenda ? leif@vaadin.com lördag 24 januari 15
Advertisement