From 694a588f94785431d012daa8d001f2f931aec852 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Leif=20=C3=85strand?= Date: Thu, 31 May 2012 23:12:57 +0300 Subject: [PATCH] Add DiffJSONSerializer for updating existing objects (#8879) This is work in progress towards using declared types for data received from the server. --- .../gwt/client/ApplicationConnection.java | 5 +- .../communication/DiffJSONSerializer.java | 19 +++++ .../client/communication/JSONSerializer.java | 7 +- .../gwt/client/communication/JsonDecoder.java | 65 +++++++------- .../URLReference_Serializer.java | 6 +- .../widgetsetutils/SerializerGenerator.java | 84 +++++++++++-------- 6 files changed, 107 insertions(+), 79 deletions(-) create mode 100644 src/com/vaadin/terminal/gwt/client/communication/DiffJSONSerializer.java diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index 530fd546db..c7ec5236b0 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -1412,7 +1412,7 @@ public class ApplicationConnection { states.getJavaScriptObject(connectorId)); JsonDecoder.decodeValue(stateDataAndType, - connector.getState(), connectorMap, + connector.getState(), ApplicationConnection.this); StateChangeEvent event = GWT @@ -1578,8 +1578,7 @@ public class ApplicationConnection { Object[] parameters = new Object[parametersJson.size()]; for (int j = 0; j < parametersJson.size(); ++j) { parameters[j] = JsonDecoder.decodeValue( - (JSONArray) parametersJson.get(j), null, getConnectorMap(), - this); + (JSONArray) parametersJson.get(j), null, this); } return new MethodInvocation(connectorId, interfaceName, methodName, parameters); diff --git a/src/com/vaadin/terminal/gwt/client/communication/DiffJSONSerializer.java b/src/com/vaadin/terminal/gwt/client/communication/DiffJSONSerializer.java new file mode 100644 index 0000000000..29cb714828 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/DiffJSONSerializer.java @@ -0,0 +1,19 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.communication; + +import com.google.gwt.json.client.JSONValue; +import com.vaadin.terminal.gwt.client.ApplicationConnection; + +public interface DiffJSONSerializer extends JSONSerializer { + /** + * Update the target object in place based on the passed JSON data. + * + * @param target + * @param jsonValue + * @param connection + */ + public void update(T target, Type type, JSONValue jsonValue, + ApplicationConnection connection); +} diff --git a/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java b/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java index f7b3df6b05..fe879b2fa7 100644 --- a/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java +++ b/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java @@ -34,14 +34,9 @@ public interface JSONSerializer { * * @param jsonValue * JSON map from property name to property value - * @param target - * The object to write the deserialized values to - * @param idMapper - * mapper from paintable id to paintable, used to decode - * references to paintables * @return A deserialized object */ - T deserialize(JSONValue jsonValue, T target, ConnectorMap idMapper, + T deserialize(Type type, JSONValue jsonValue, ApplicationConnection connection); /** diff --git a/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java b/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java index 8df92a141e..8d22481783 100644 --- a/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java +++ b/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java @@ -49,26 +49,25 @@ public class JsonDecoder { * @return decoded value (does not contain JSON types) */ public static Object decodeValue(JSONArray jsonArray, Object target, - ConnectorMap idMapper, ApplicationConnection connection) { + ApplicationConnection connection) { String type = ((JSONString) jsonArray.get(0)).stringValue(); - return decodeValue(type, jsonArray.get(1), target, idMapper, connection); + return decodeValue(type, jsonArray.get(1), target, connection); } private static Object decodeValue(String variableType, JSONValue value, - Object target, ConnectorMap idMapper, - ApplicationConnection connection) { + Object target, ApplicationConnection connection) { Object val = null; // TODO type checks etc. if (JsonEncoder.VTYPE_NULL.equals(variableType)) { val = null; } else if (JsonEncoder.VTYPE_ARRAY.equals(variableType)) { - val = decodeArray((JSONArray) value, idMapper, connection); + val = decodeArray((JSONArray) value, connection); } else if (JsonEncoder.VTYPE_MAP.equals(variableType)) { - val = decodeMap((JSONObject) value, idMapper, connection); + val = decodeMap((JSONObject) value, connection); } else if (JsonEncoder.VTYPE_LIST.equals(variableType)) { - val = decodeList((JSONArray) value, idMapper, connection); + val = decodeList((JSONArray) value, connection); } else if (JsonEncoder.VTYPE_SET.equals(variableType)) { - val = decodeSet((JSONArray) value, idMapper, connection); + val = decodeSet((JSONArray) value, connection); } else if (JsonEncoder.VTYPE_STRINGARRAY.equals(variableType)) { val = decodeStringArray((JSONArray) value); } else if (JsonEncoder.VTYPE_STRING.equals(variableType)) { @@ -89,39 +88,44 @@ public class JsonDecoder { // TODO handle properly val = Boolean.valueOf(String.valueOf(value)); } else if (JsonEncoder.VTYPE_CONNECTOR.equals(variableType)) { - val = idMapper.getConnector(((JSONString) value).stringValue()); + val = ConnectorMap.get(connection).getConnector( + ((JSONString) value).stringValue()); } else { - return decodeObject(variableType, value, target, idMapper, + return decodeObject(new Type(variableType, null), value, target, connection); } return val; } - private static Object decodeObject(String variableType, - JSONValue encodedValue, Object target, ConnectorMap idMapper, - ApplicationConnection connection) { + private static Object decodeObject(Type type, JSONValue encodedValue, + Object target, ApplicationConnection connection) { // object, class name as type JSONSerializer serializer = connection.getSerializerMap() - .getSerializer(variableType); + .getSerializer(type.getBaseTypeName()); // TODO handle case with no serializer found - Object object = serializer.deserialize(encodedValue, target, idMapper, - connection); - return object; + + if (target != null && serializer instanceof DiffJSONSerializer) { + DiffJSONSerializer diffSerializer = (DiffJSONSerializer) serializer; + diffSerializer.update(target, type, encodedValue, connection); + return target; + } else { + Object object = serializer.deserialize(type, encodedValue, + connection); + return object; + } } private static Map decodeMap(JSONObject jsonMap, - ConnectorMap idMapper, ApplicationConnection connection) { + ApplicationConnection connection) { HashMap map = new HashMap(); Iterator it = jsonMap.keySet().iterator(); while (it.hasNext()) { String key = it.next(); JSONArray encodedKey = (JSONArray) JSONParser.parseStrict(key); JSONArray encodedValue = (JSONArray) jsonMap.get(key); - Object decodedKey = decodeValue(encodedKey, null, idMapper, - connection); - Object decodedValue = decodeValue(encodedValue, null, idMapper, - connection); + Object decodedKey = decodeValue(encodedKey, null, connection); + Object decodedValue = decodeValue(encodedValue, null, connection); map.put(decodedKey, decodedValue); } return map; @@ -137,32 +141,31 @@ public class JsonDecoder { } private static Object[] decodeArray(JSONArray jsonArray, - ConnectorMap idMapper, ApplicationConnection connection) { - List list = decodeList(jsonArray, idMapper, connection); + ApplicationConnection connection) { + List list = decodeList(jsonArray, connection); return list.toArray(new Object[list.size()]); } private static List decodeList(JSONArray jsonArray, - ConnectorMap idMapper, ApplicationConnection connection) { + ApplicationConnection connection) { List tokens = new ArrayList(); - decodeIntoCollection(jsonArray, idMapper, connection, tokens); + decodeIntoCollection(jsonArray, connection, tokens); return tokens; } private static Set decodeSet(JSONArray jsonArray, - ConnectorMap idMapper, ApplicationConnection connection) { + ApplicationConnection connection) { Set tokens = new HashSet(); - decodeIntoCollection(jsonArray, idMapper, connection, tokens); + decodeIntoCollection(jsonArray, connection, tokens); return tokens; } private static void decodeIntoCollection(JSONArray jsonArray, - ConnectorMap idMapper, ApplicationConnection connection, - Collection tokens) { + ApplicationConnection connection, Collection tokens) { for (int i = 0; i < jsonArray.size(); ++i) { // each entry always has two elements: type and value JSONArray entryArray = (JSONArray) jsonArray.get(i); - tokens.add(decodeValue(entryArray, null, idMapper, connection)); + tokens.add(decodeValue(entryArray, null, connection)); } } } diff --git a/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java b/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java index 2ee7df7f6d..1ae8cc4755 100644 --- a/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java +++ b/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java @@ -12,14 +12,14 @@ import com.vaadin.terminal.gwt.client.ConnectorMap; public class URLReference_Serializer implements JSONSerializer { - public URLReference deserialize(JSONValue jsonValue, URLReference target, - ConnectorMap idMapper, ApplicationConnection connection) { + public URLReference deserialize(Type type, JSONValue jsonValue, + ApplicationConnection connection) { URLReference reference = GWT.create(URLReference.class); JSONObject json = (JSONObject) jsonValue; if (json.containsKey("URL")) { JSONArray jsonURL = (JSONArray) json.get("URL"); String URL = (String) JsonDecoder.decodeValue(jsonURL, null, - idMapper, connection); + connection); reference.setURL(connection.translateVaadinUri(URL)); } return reference; diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java index bc031f4bdb..6aa6b073ee 100644 --- a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java @@ -30,6 +30,7 @@ import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; import com.google.gwt.user.rebind.SourceWriter; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.ConnectorMap; +import com.vaadin.terminal.gwt.client.communication.DiffJSONSerializer; import com.vaadin.terminal.gwt.client.communication.JSONSerializer; import com.vaadin.terminal.gwt.client.communication.JsonDecoder; import com.vaadin.terminal.gwt.client.communication.JsonEncoder; @@ -107,13 +108,20 @@ public class SerializerGenerator extends Generator { serializerClassName); composer.addImport(GWT.class.getName()); composer.addImport(JSONArray.class.getName()); + composer.addImport(com.vaadin.terminal.gwt.client.communication.Type.class + .getName()); // composer.addImport(JSONObject.class.getName()); // composer.addImport(VPaintableMap.class.getName()); composer.addImport(JsonDecoder.class.getName()); // composer.addImport(VaadinSerializer.class.getName()); - composer.addImplementedInterface(JSONSerializer.class.getName() + "<" - + beanQualifiedSourceName + ">"); + if (isEnum) { + composer.addImplementedInterface(JSONSerializer.class.getName() + + "<" + beanQualifiedSourceName + ">"); + } else { + composer.addImplementedInterface(DiffJSONSerializer.class.getName() + + "<" + beanQualifiedSourceName + ">"); + } SourceWriter sourceWriter = composer.createSourceWriter(context, printWriter); @@ -138,20 +146,39 @@ public class SerializerGenerator extends Generator { writeBeanSerializer(logger, sourceWriter, beanType); } // } + sourceWriter.outdent(); sourceWriter.println("}"); + sourceWriter.println(); + + // Updater + // public void update(T target, Type type, JSONValue jsonValue, + // ApplicationConnection connection); + if (!isEnum) { + sourceWriter.println("public void update(" + + beanQualifiedSourceName + " target, Type type, " + + JSONValue.class.getName() + " jsonValue, " + + ApplicationConnection.class.getName() + " connection) {"); + sourceWriter.indent(); + + writeBeanDeserializer(logger, sourceWriter, beanType, true); + + sourceWriter.outdent(); + sourceWriter.println("}"); + } // Deserializer + // T deserialize(Type type, JSONValue jsonValue, ApplicationConnection + // connection); sourceWriter.println("public " + beanQualifiedSourceName - + " deserialize(" + JSONValue.class.getName() + " jsonValue, " - + beanQualifiedSourceName + " target, " - + ConnectorMap.class.getName() + " idMapper, " - + ApplicationConnection.class.getName() + " connection) {"); + + " deserialize(Type type, " + JSONValue.class.getName() + + " jsonValue, " + ApplicationConnection.class.getName() + + " connection) {"); sourceWriter.indent(); if (isEnum) { writeEnumDeserializer(logger, sourceWriter, beanType.isEnum()); } else { - writeBeanDeserializer(logger, sourceWriter, beanType); + writeBeanDeserializer(logger, sourceWriter, beanType, false); } sourceWriter.println("}"); sourceWriter.outdent(); @@ -183,18 +210,14 @@ public class SerializerGenerator extends Generator { } private void writeBeanDeserializer(TreeLogger logger, - SourceWriter sourceWriter, JClassType beanType) { + SourceWriter sourceWriter, JClassType beanType, boolean update) { String beanQualifiedSourceName = beanType.getQualifiedSourceName(); - // if (target == null) { - sourceWriter.println("if (target == null) {"); - sourceWriter.indent(); - - // target = GWT.create(VButtonState.class); - sourceWriter.println("target = GWT.create(" + beanQualifiedSourceName - + ".class);"); - sourceWriter.outdent(); - sourceWriter.println("}"); + if (!update) { + sourceWriter.println(beanQualifiedSourceName + + " target = GWT.create(" + beanQualifiedSourceName + + ".class);"); + } // JSONOBject json = (JSONObject)jsonValue; sourceWriter.println(JSONObject.class.getName() + " json = (" @@ -230,37 +253,26 @@ public class SerializerGenerator extends Generator { fieldType = setterParameterType.getQualifiedSourceName(); } - // String referenceValue; - sourceWriter.println(fieldType + " referenceValue;"); - // if (target == null) { - sourceWriter.println("if (target == null) {"); - sourceWriter.indent(); - // referenceValue = null; - sourceWriter.println("referenceValue = null;"); - // } else { - sourceWriter.println("} else {"); - // referenceValue = target.getHeight(); - sourceWriter.println("referenceValue = target." + getterName - + "();"); - // } - sourceWriter.outdent(); - sourceWriter.println("}"); + // String referenceValue = target.getHeight(); + sourceWriter.println(fieldType + " referenceValue = target." + + getterName + "();"); // target.setHeight((String) // JsonDecoder.decodeValue(jsonFieldValue,referenceValue, idMapper, // connection)); sourceWriter.println("target." + setterName + "((" + fieldType + ") " + JsonDecoder.class.getName() + ".decodeValue(" - + jsonFieldName - + ", referenceValue, idMapper, connection));"); + + jsonFieldName + ", referenceValue, connection));"); // } ... end of if contains sourceWriter.println("}"); sourceWriter.outdent(); } - // return target; - sourceWriter.println("return target;"); + if (!update) { + // return target; + sourceWriter.println("return target;"); + } } -- 2.39.5