diff options
Diffstat (limited to 'src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java')
-rw-r--r-- | src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java | 224 |
1 files changed, 136 insertions, 88 deletions
diff --git a/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java b/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java index 9ed20b6c79..23a2c30cd0 100644 --- a/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java +++ b/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java @@ -5,21 +5,20 @@ package com.vaadin.terminal.gwt.client.communication; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONObject; -import com.google.gwt.json.client.JSONParser; import com.google.gwt.json.client.JSONString; import com.google.gwt.json.client.JSONValue; import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Connector; import com.vaadin.terminal.gwt.client.ConnectorMap; -import com.vaadin.terminal.gwt.client.ServerConnector; /** * Client side decoder for decodeing shared state and other values from JSON @@ -38,128 +37,177 @@ public class JsonDecoder { * 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 - * @param idMapper - * mapper between connector ID and {@link ServerConnector} - * objects + * @param jsonValue + * JSON value with encoded data * @param connection * reference to the current ApplicationConnection * @return decoded value (does not contain JSON types) */ - public static Object decodeValue(JSONArray jsonArray, Object target, - ConnectorMap idMapper, ApplicationConnection connection) { - String type = ((JSONString) jsonArray.get(0)).stringValue(); - return decodeValue(type, jsonArray.get(1), target, idMapper, connection); - } + public static Object decodeValue(Type type, JSONValue jsonValue, + Object target, ApplicationConnection connection) { - private static Object decodeValue(String variableType, JSONValue value, - Object target, ConnectorMap idMapper, - 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); - } else if (JsonEncoder.VTYPE_MAP.equals(variableType)) { - val = decodeMap((JSONObject) value, idMapper, connection); - } else if (JsonEncoder.VTYPE_LIST.equals(variableType)) { - val = decodeList((JSONArray) value, idMapper, connection); - } else if (JsonEncoder.VTYPE_SET.equals(variableType)) { - val = decodeSet((JSONArray) value, idMapper, connection); - } else if (JsonEncoder.VTYPE_STRINGARRAY.equals(variableType)) { - val = decodeStringArray((JSONArray) value); - } else if (JsonEncoder.VTYPE_STRING.equals(variableType)) { - val = ((JSONString) value).stringValue(); - } else if (JsonEncoder.VTYPE_INTEGER.equals(variableType)) { + // Null is null, regardless of type + if (jsonValue.isNull() != null) { + return null; + } + + String baseTypeName = type.getBaseTypeName(); + if (Map.class.getName().equals(baseTypeName) + || HashMap.class.getName().equals(baseTypeName)) { + return decodeMap(type, jsonValue, connection); + } else if (List.class.getName().equals(baseTypeName) + || ArrayList.class.getName().equals(baseTypeName)) { + return decodeList(type, (JSONArray) jsonValue, connection); + } else if (Set.class.getName().equals(baseTypeName)) { + return decodeSet(type, (JSONArray) jsonValue, connection); + } else if (String.class.getName().equals(baseTypeName)) { + return ((JSONString) jsonValue).stringValue(); + } else if (Integer.class.getName().equals(baseTypeName)) { + return Integer.valueOf(String.valueOf(jsonValue)); + } else if (Long.class.getName().equals(baseTypeName)) { + // TODO handle properly + return Long.valueOf(String.valueOf(jsonValue)); + } else if (Float.class.getName().equals(baseTypeName)) { // TODO handle properly - val = Integer.valueOf(String.valueOf(value)); - } else if (JsonEncoder.VTYPE_LONG.equals(variableType)) { + return Float.valueOf(String.valueOf(jsonValue)); + } else if (Double.class.getName().equals(baseTypeName)) { // TODO handle properly - val = Long.valueOf(String.valueOf(value)); - } else if (JsonEncoder.VTYPE_FLOAT.equals(variableType)) { + return Double.valueOf(String.valueOf(jsonValue)); + } else if (Boolean.class.getName().equals(baseTypeName)) { // TODO handle properly - val = Float.valueOf(String.valueOf(value)); - } else if (JsonEncoder.VTYPE_DOUBLE.equals(variableType)) { + return Boolean.valueOf(String.valueOf(jsonValue)); + } else if (Byte.class.getName().equals(baseTypeName)) { // TODO handle properly - val = Double.valueOf(String.valueOf(value)); - } else if (JsonEncoder.VTYPE_BOOLEAN.equals(variableType)) { + return Byte.valueOf(String.valueOf(jsonValue)); + } else if (Character.class.getName().equals(baseTypeName)) { // TODO handle properly - val = Boolean.valueOf(String.valueOf(value)); - } else if (JsonEncoder.VTYPE_CONNECTOR.equals(variableType)) { - val = idMapper.getConnector(((JSONString) value).stringValue()); + return Character.valueOf(((JSONString) jsonValue).stringValue() + .charAt(0)); + } else if (Connector.class.getName().equals(baseTypeName)) { + return ConnectorMap.get(connection).getConnector( + ((JSONString) jsonValue).stringValue()); } else { - return decodeObject(variableType, value, target, idMapper, - connection); + return decodeObject(type, jsonValue, target, connection); } - - return val; } - private static Object decodeObject(String variableType, - JSONValue encodedValue, Object target, ConnectorMap idMapper, - ApplicationConnection connection) { - // object, class name as type + private static Object decodeObject(Type type, JSONValue jsonValue, + Object target, ApplicationConnection connection) { JSONSerializer<Object> 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; + // Currently getSerializer throws exception if not found + + if (target != null && serializer instanceof DiffJSONSerializer<?>) { + DiffJSONSerializer<Object> diffSerializer = (DiffJSONSerializer<Object>) serializer; + diffSerializer.update(target, type, jsonValue, connection); + return target; + } else { + Object object = serializer.deserialize(type, jsonValue, connection); + return object; + } } - private static Map<Object, Object> decodeMap(JSONObject jsonMap, - ConnectorMap idMapper, ApplicationConnection connection) { - HashMap<Object, Object> map = new HashMap<Object, Object>(); - Iterator<String> 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, + private static Map<Object, Object> decodeMap(Type type, JSONValue jsonMap, + ApplicationConnection connection) { + // Client -> server encodes empty map as an empty array because of + // #8906. Do the same for server -> client to maintain symmetry. + if (jsonMap instanceof JSONArray) { + JSONArray array = (JSONArray) jsonMap; + if (array.size() == 0) { + return new HashMap<Object, Object>(); + } + } + + Type keyType = type.getParameterTypes()[0]; + Type valueType = type.getParameterTypes()[1]; + + if (keyType.getBaseTypeName().equals(String.class.getName())) { + return decodeStringMap(valueType, jsonMap, connection); + } else if (keyType.getBaseTypeName().equals(Connector.class.getName())) { + return decodeConnectorMap(valueType, jsonMap, connection); + } else { + return decodeObjectMap(keyType, valueType, jsonMap, connection); + } + } + + private static Map<Object, Object> decodeObjectMap(Type keyType, + Type valueType, JSONValue jsonValue, + ApplicationConnection connection) { + Map<Object, Object> map = new HashMap<Object, Object>(); + + JSONArray mapArray = (JSONArray) jsonValue; + JSONArray keys = (JSONArray) mapArray.get(0); + JSONArray values = (JSONArray) mapArray.get(1); + + assert (keys.size() == values.size()); + + for (int i = 0; i < keys.size(); i++) { + Object decodedKey = decodeValue(keyType, keys.get(i), null, connection); - Object decodedValue = decodeValue(encodedValue, null, idMapper, + Object decodedValue = decodeValue(valueType, values.get(i), null, connection); + map.put(decodedKey, decodedValue); } + return map; } - private static String[] decodeStringArray(JSONArray jsonArray) { - int size = jsonArray.size(); - List<String> tokens = new ArrayList<String>(size); - for (int i = 0; i < size; ++i) { - tokens.add(String.valueOf(jsonArray.get(i))); + private static Map<Object, Object> decodeConnectorMap(Type valueType, + JSONValue jsonValue, ApplicationConnection connection) { + Map<Object, Object> map = new HashMap<Object, Object>(); + + JSONObject jsonMap = (JSONObject) jsonValue; + ConnectorMap connectorMap = ConnectorMap.get(connection); + + for (String connectorId : jsonMap.keySet()) { + Object value = decodeValue(valueType, jsonMap.get(connectorId), + null, connection); + map.put(connectorMap.getConnector(connectorId), value); } - return tokens.toArray(new String[tokens.size()]); + + return map; } - private static Object[] decodeArray(JSONArray jsonArray, - ConnectorMap idMapper, ApplicationConnection connection) { - List<Object> list = decodeList(jsonArray, idMapper, connection); - return list.toArray(new Object[list.size()]); + private static Map<Object, Object> decodeStringMap(Type valueType, + JSONValue jsonValue, ApplicationConnection connection) { + Map<Object, Object> map = new HashMap<Object, Object>(); + + JSONObject jsonMap = (JSONObject) jsonValue; + + for (String key : jsonMap.keySet()) { + Object value = decodeValue(valueType, jsonMap.get(key), null, + connection); + map.put(key, value); + } + + return map; } - private static List<Object> decodeList(JSONArray jsonArray, - ConnectorMap idMapper, ApplicationConnection connection) { + private static List<Object> decodeList(Type type, JSONArray jsonArray, + ApplicationConnection connection) { List<Object> tokens = new ArrayList<Object>(); - 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)); - } + decodeIntoCollection(type.getParameterTypes()[0], jsonArray, + connection, tokens); return tokens; } - private static Set<Object> decodeSet(JSONArray jsonArray, - ConnectorMap idMapper, ApplicationConnection connection) { + private static Set<Object> decodeSet(Type type, JSONArray jsonArray, + ApplicationConnection connection) { Set<Object> tokens = new HashSet<Object>(); + decodeIntoCollection(type.getParameterTypes()[0], jsonArray, + connection, tokens); + return tokens; + } + + private static void decodeIntoCollection(Type childType, + JSONArray jsonArray, ApplicationConnection connection, + Collection<Object> 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)); + JSONValue entryValue = jsonArray.get(i); + tokens.add(decodeValue(childType, entryValue, null, connection)); } - return tokens; } } |