From b1378a63698af453a88477b6ca03a5ec837a90b2 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Fri, 9 Mar 2012 16:10:21 +0200 Subject: [PATCH] #8515 Added serialization support for Lists containing supported types. --- .../gwt/client/ApplicationConnection.java | 4 +- .../gwt/client/communication/JsonDecoder.java | 41 +++++++++------- .../gwt/client/communication/JsonEncoder.java | 6 ++- .../URLReference_Serializer.java | 2 +- .../vaadin/terminal/gwt/server/JsonCodec.java | 49 ++++++++++++++----- .../widgetsetutils/SerializerGenerator.java | 6 +-- .../SerializerMapGenerator.java | 10 +++- 7 files changed, 78 insertions(+), 40 deletions(-) diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index c889a65ce5..f956f56f92 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -1196,7 +1196,7 @@ public class ApplicationConnection { JSONArray stateDataAndType = new JSONArray( states.getJavaScriptObject(connectorId)); - Object state = JsonDecoder.convertValue( + Object state = JsonDecoder.decodeValue( stateDataAndType, connectorMap, ApplicationConnection.this); @@ -1317,7 +1317,7 @@ public class ApplicationConnection { JSONArray parametersJson = (JSONArray) rpcCall.get(3); Object[] parameters = new Object[parametersJson.size()]; for (int j = 0; j < parametersJson.size(); ++j) { - parameters[j] = JsonDecoder.convertValue( + parameters[j] = JsonDecoder.decodeValue( (JSONArray) parametersJson.get(j), getConnectorMap(), this); } return new MethodInvocation(connectorId, interfaceName, methodName, diff --git a/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java b/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java index 2250bbbb8d..5fbb801e87 100644 --- a/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java +++ b/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java @@ -19,7 +19,7 @@ import com.vaadin.terminal.gwt.client.Connector; import com.vaadin.terminal.gwt.client.ConnectorMap; /** - * Client side decoder for converting shared state and other values from JSON + * Client side decoder for decodeing shared state and other values from JSON * received from the server. * * Currently, basic data types as well as Map, String[] and Object[] are @@ -33,8 +33,8 @@ public class JsonDecoder { static SerializerMap serializerMap = GWT.create(SerializerMap.class); /** - * Convert a JSON array with two elements (type and value) into a - * client-side type, recursively if necessary. + * Decode a JSON array with two elements (type and value) into a client-side + * type, recursively if necessary. * * @param jsonArray * JSON array with two elements @@ -42,26 +42,28 @@ public class JsonDecoder { * mapper between connector ID and {@link Connector} objects * @param connection * reference to the current ApplicationConnection - * @return converted value (does not contain JSON types) + * @return decoded value (does not contain JSON types) */ - public static Object convertValue(JSONArray jsonArray, + public static Object decodeValue(JSONArray jsonArray, ConnectorMap idMapper, ApplicationConnection connection) { String type = ((JSONString) jsonArray.get(0)).stringValue(); - return convertValue(type, jsonArray.get(1), idMapper, connection); + return decodeValue(type, jsonArray.get(1), idMapper, connection); } - private static Object convertValue(String variableType, Object value, + private static Object decodeValue(String variableType, Object value, ConnectorMap idMapper, ApplicationConnection connection) { Object val = null; // TODO type checks etc. if (JsonEncoder.VTYPE_UNDEFINED.equals(variableType)) { val = null; } else if (JsonEncoder.VTYPE_ARRAY.equals(variableType)) { - val = convertArray((JSONArray) value, idMapper, connection); + val = decodeArray((JSONArray) value, idMapper, connection); } else if (JsonEncoder.VTYPE_MAP.equals(variableType)) { - val = convertMap((JSONObject) value, idMapper, connection); + val = decodeMap((JSONObject) value, idMapper, connection); + } else if (JsonEncoder.VTYPE_LIST.equals(variableType)) { + val = decodeList((JSONArray) value, idMapper, connection); } else if (JsonEncoder.VTYPE_STRINGARRAY.equals(variableType)) { - val = convertStringArray((JSONArray) value); + val = decodeStringArray((JSONArray) value); } else if (JsonEncoder.VTYPE_STRING.equals(variableType)) { val = ((JSONString) value).stringValue(); } else if (JsonEncoder.VTYPE_INTEGER.equals(variableType)) { @@ -95,20 +97,20 @@ public class JsonDecoder { return val; } - private static Map convertMap(JSONObject jsonMap, + private static Map decodeMap(JSONObject jsonMap, ConnectorMap idMapper, ApplicationConnection connection) { HashMap map = new HashMap(); Iterator it = jsonMap.keySet().iterator(); while (it.hasNext()) { String key = it.next(); map.put(key, - convertValue((JSONArray) jsonMap.get(key), idMapper, + decodeValue((JSONArray) jsonMap.get(key), idMapper, connection)); } return map; } - private static String[] convertStringArray(JSONArray jsonArray) { + private static String[] decodeStringArray(JSONArray jsonArray) { int size = jsonArray.size(); List tokens = new ArrayList(size); for (int i = 0; i < size; ++i) { @@ -117,15 +119,20 @@ public class JsonDecoder { return tokens.toArray(new String[tokens.size()]); } - private static Object[] convertArray(JSONArray jsonArray, + private static Object[] decodeArray(JSONArray jsonArray, + ConnectorMap idMapper, ApplicationConnection connection) { + List list = decodeList(jsonArray, idMapper, connection); + return list.toArray(new Object[list.size()]); + } + + private static List decodeList(JSONArray jsonArray, ConnectorMap idMapper, ApplicationConnection connection) { List tokens = new ArrayList(); 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(convertValue(entryArray, idMapper, connection)); + tokens.add(decodeValue(entryArray, idMapper, connection)); } - return tokens.toArray(new Object[tokens.size()]); + return tokens; } - } diff --git a/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java b/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java index c7d49875d7..874313ba02 100644 --- a/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java +++ b/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java @@ -4,6 +4,7 @@ package com.vaadin.terminal.gwt.client.communication; +import java.util.List; import java.util.Map; import com.google.gwt.json.client.JSONArray; @@ -39,8 +40,7 @@ public class JsonEncoder { public static final String VTYPE_ARRAY = "a"; public static final String VTYPE_STRINGARRAY = "c"; public static final String VTYPE_MAP = "m"; - // TODO this will be replaced by the shared state class name - public static final String VTYPE_SHAREDSTATE = "t"; + public static final String VTYPE_LIST = "L"; // TODO is this needed? public static final String VTYPE_UNDEFINED = "u"; @@ -135,6 +135,8 @@ public class JsonEncoder { return VTYPE_DOUBLE; } else if (value instanceof Long) { return VTYPE_LONG; + } else if (value instanceof List) { + return VTYPE_LIST; } else if (value instanceof Enum) { return VTYPE_STRING; // transported as string representation } else if (value instanceof String[]) { 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 24053d2c15..034d283740 100644 --- a/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java +++ b/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java @@ -12,7 +12,7 @@ public class URLReference_Serializer implements JSONSerializer { ConnectorMap idMapper, ApplicationConnection connection) { URLReference reference = GWT.create(URLReference.class); JSONArray jsonURL = (JSONArray) jsonValue.get("URL"); - String URL = (String) JsonDecoder.convertValue(jsonURL, idMapper, + String URL = (String) JsonDecoder.decodeValue(jsonURL, idMapper, connection); reference.setURL(connection.translateVaadinUri(URL)); return reference; diff --git a/src/com/vaadin/terminal/gwt/server/JsonCodec.java b/src/com/vaadin/terminal/gwt/server/JsonCodec.java index 0a617470a5..4b3f41508e 100644 --- a/src/com/vaadin/terminal/gwt/server/JsonCodec.java +++ b/src/com/vaadin/terminal/gwt/server/JsonCodec.java @@ -45,6 +45,7 @@ public class JsonCodec implements Serializable { registerType(String[].class, JsonEncoder.VTYPE_STRINGARRAY); registerType(Object[].class, JsonEncoder.VTYPE_ARRAY); registerType(Map.class, JsonEncoder.VTYPE_MAP); + registerType(List.class, JsonEncoder.VTYPE_LIST); } private static void registerType(Class type, String transportType) { @@ -65,19 +66,21 @@ public class JsonCodec implements Serializable { */ public static Object decode(JSONArray value, PaintableIdMapper idMapper) throws JSONException { - return convertVariableValue(value.getString(0), value.get(1), idMapper); + return decodeVariableValue(value.getString(0), value.get(1), idMapper); } - private static Object convertVariableValue(String variableType, + private static Object decodeVariableValue(String variableType, Object value, PaintableIdMapper idMapper) throws JSONException { Object val = null; // TODO type checks etc. if (JsonEncoder.VTYPE_ARRAY.equals(variableType)) { - val = convertArray((JSONArray) value, idMapper); + val = decodeArray((JSONArray) value, idMapper); + } else if (JsonEncoder.VTYPE_LIST.equals(variableType)) { + val = decodeList((JSONArray) value, idMapper); } else if (JsonEncoder.VTYPE_MAP.equals(variableType)) { - val = convertMap((JSONObject) value, idMapper); + val = decodeMap((JSONObject) value, idMapper); } else if (JsonEncoder.VTYPE_STRINGARRAY.equals(variableType)) { - val = convertStringArray((JSONArray) value); + val = decodeStringArray((JSONArray) value); } else if (JsonEncoder.VTYPE_STRING.equals(variableType)) { val = value; } else if (JsonEncoder.VTYPE_INTEGER.equals(variableType)) { @@ -107,7 +110,7 @@ public class JsonCodec implements Serializable { return val; } - private static Object convertMap(JSONObject jsonMap, + private static Object decodeMap(JSONObject jsonMap, PaintableIdMapper idMapper) throws JSONException { HashMap map = new HashMap(); Iterator it = jsonMap.keys(); @@ -118,7 +121,7 @@ public class JsonCodec implements Serializable { return map; } - private static String[] convertStringArray(JSONArray jsonArray) + private static String[] decodeStringArray(JSONArray jsonArray) throws JSONException { int length = jsonArray.length(); List tokens = new ArrayList(length); @@ -128,15 +131,21 @@ public class JsonCodec implements Serializable { return tokens.toArray(new String[tokens.size()]); } - private static Object convertArray(JSONArray jsonArray, + private static Object decodeArray(JSONArray jsonArray, PaintableIdMapper idMapper) throws JSONException { - List tokens = new ArrayList(); + List list = decodeList(jsonArray, idMapper); + return list.toArray(new Object[list.size()]); + } + + private static List decodeList(JSONArray jsonArray, + PaintableIdMapper idMapper) throws JSONException { + List list = new ArrayList(); for (int i = 0; i < jsonArray.length(); ++i) { // each entry always has two elements: type and value JSONArray entryArray = jsonArray.getJSONArray(i); - tokens.add(decode(entryArray, idMapper)); + list.add(decode(entryArray, idMapper)); } - return tokens.toArray(new Object[tokens.size()]); + return list; } /** @@ -176,6 +185,10 @@ public class JsonCodec implements Serializable { return combineTypeAndValue(JsonEncoder.VTYPE_BOOLEAN, value); } else if (value instanceof Number) { return combineTypeAndValue(getTransportType(value), value); + } else if (value instanceof List) { + List list = (List) value; + JSONArray jsonArray = encodeList(list, idMapper); + return combineTypeAndValue(JsonEncoder.VTYPE_LIST, jsonArray); } else if (value instanceof Object[]) { Object[] array = (Object[]) value; JSONArray jsonArray = encodeArrayContents(array, idMapper); @@ -267,9 +280,19 @@ public class JsonCodec implements Serializable { private static JSONArray encodeArrayContents(Object[] array, PaintableIdMapper idMapper) throws JSONException { JSONArray jsonArray = new JSONArray(); - for (int i = 0; i < array.length; ++i) { + for (Object o : array) { + // TODO handle object graph loops? + jsonArray.put(encode(o, idMapper)); + } + return jsonArray; + } + + private static JSONArray encodeList(List list, PaintableIdMapper idMapper) + throws JSONException { + JSONArray jsonArray = new JSONArray(); + for (Object o : list) { // TODO handle object graph loops? - jsonArray.put(encode(array[i], idMapper)); + jsonArray.put(encode(o, idMapper)); } return jsonArray; } diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java index f80b7a3f27..bb05432964 100644 --- a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java @@ -175,7 +175,7 @@ public class SerializerGenerator extends Generator { + " = (JSONArray) jsonValue.get(\"" + fieldName + "\");"); // state.setHeight((String) - // JsonDecoder.convertValue(jsonFieldValue,idMapper, connection)); + // JsonDecoder.decodeValue(jsonFieldValue,idMapper, connection)); String fieldType; JPrimitiveType primitiveType = setterParameterType.isPrimitive(); @@ -187,8 +187,8 @@ public class SerializerGenerator extends Generator { } sourceWriter.println("state." + setterName + "((" + fieldType - + ") JsonDecoder.convertValue(" + jsonFieldName - + ", idMapper, connection));"); + + ") " + JsonDecoder.class.getName() + ".decodeValue(" + + jsonFieldName + ", idMapper, connection));"); } // return state; diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java index c2a54030f7..52b599253f 100644 --- a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java @@ -219,8 +219,14 @@ public class SerializerMapGenerator extends Generator { continue; } - serializableTypes.add(setterType.isClass()); - findSubTypesNeedingSerializers(type, serializableTypes); + JClassType setterTypeClass = setterType.isClass(); + if (setterTypeClass != null) { + // setterTypeClass is null at least for List. It is + // possible that we need to handle the cases somehow, for + // instance for List. + serializableTypes.add(setterTypeClass); + findSubTypesNeedingSerializers(type, serializableTypes); + } } } -- 2.39.5