import com.google.gwt.http.client.RequestException; | import com.google.gwt.http.client.RequestException; | ||||
import com.google.gwt.http.client.Response; | import com.google.gwt.http.client.Response; | ||||
import com.google.gwt.json.client.JSONArray; | import com.google.gwt.json.client.JSONArray; | ||||
import com.google.gwt.json.client.JSONObject; | |||||
import com.google.gwt.json.client.JSONString; | import com.google.gwt.json.client.JSONString; | ||||
import com.google.gwt.regexp.shared.MatchResult; | import com.google.gwt.regexp.shared.MatchResult; | ||||
import com.google.gwt.regexp.shared.RegExp; | import com.google.gwt.regexp.shared.RegExp; | ||||
.getConnector(connectorId); | .getConnector(connectorId); | ||||
if (null != connector) { | if (null != connector) { | ||||
JSONArray stateDataAndType = new JSONArray( | |||||
JSONObject stateDataAndType = new JSONObject( | |||||
states.getJavaScriptObject(connectorId)); | states.getJavaScriptObject(connectorId)); | ||||
SharedState state = connector.getState(); | SharedState state = connector.getState(); | ||||
Object[] parameters = new Object[parametersJson.size()]; | Object[] parameters = new Object[parametersJson.size()]; | ||||
for (int j = 0; j < parametersJson.size(); ++j) { | for (int j = 0; j < parametersJson.size(); ++j) { | ||||
parameters[j] = JsonDecoder.decodeValue(parameterTypes[j], | parameters[j] = JsonDecoder.decodeValue(parameterTypes[j], | ||||
(JSONArray) parametersJson.get(j), null, this); | |||||
parametersJson.get(j), null, this); | |||||
} | } | ||||
methodInvocation.setParameters(parameters); | methodInvocation.setParameters(parameters); |
import com.vaadin.terminal.gwt.client.ApplicationConnection; | import com.vaadin.terminal.gwt.client.ApplicationConnection; | ||||
import com.vaadin.terminal.gwt.client.Connector; | import com.vaadin.terminal.gwt.client.Connector; | ||||
import com.vaadin.terminal.gwt.client.ConnectorMap; | 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 | * Client side decoder for decodeing shared state and other values from JSON | ||||
* Decode a JSON array with two elements (type and value) into a client-side | * Decode a JSON array with two elements (type and value) into a client-side | ||||
* type, recursively if necessary. | * 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 | * @param connection | ||||
* reference to the current ApplicationConnection | * reference to the current ApplicationConnection | ||||
* @return decoded value (does not contain JSON types) | * @return decoded value (does not contain JSON types) | ||||
*/ | */ | ||||
public static Object decodeValue(Type type, JSONArray jsonArray, | |||||
Object target, ApplicationConnection connection) { | |||||
return decodeValue(type, jsonArray.get(1), target, connection); | |||||
} | |||||
private static Object decodeValue(Type type, JSONValue jsonValue, | |||||
public static Object decodeValue(Type type, JSONValue jsonValue, | |||||
Object target, ApplicationConnection connection) { | Object target, ApplicationConnection connection) { | ||||
// Null is null, regardless of type | // Null is null, regardless of type | ||||
Iterator<String> it = jsonMap.keySet().iterator(); | Iterator<String> it = jsonMap.keySet().iterator(); | ||||
while (it.hasNext()) { | while (it.hasNext()) { | ||||
String key = it.next(); | String key = it.next(); | ||||
JSONArray encodedKey = (JSONArray) JSONParser.parseStrict(key); | |||||
JSONArray encodedValue = (JSONArray) jsonMap.get(key); | |||||
JSONValue encodedKey = JSONParser.parseStrict(key); | |||||
JSONValue encodedValue = jsonMap.get(key); | |||||
Object decodedKey = decodeValue(type.getParameterTypes()[0], | Object decodedKey = decodeValue(type.getParameterTypes()[0], | ||||
encodedKey, null, connection); | encodedKey, null, connection); | ||||
Object decodedValue = decodeValue(type.getParameterTypes()[1], | Object decodedValue = decodeValue(type.getParameterTypes()[1], | ||||
Collection<Object> tokens) { | Collection<Object> tokens) { | ||||
for (int i = 0; i < jsonArray.size(); ++i) { | for (int i = 0; i < jsonArray.size(); ++i) { | ||||
// each entry always has two elements: type and value | // each entry always has two elements: type and value | ||||
JSONArray entryArray = (JSONArray) jsonArray.get(i); | |||||
tokens.add(decodeValue(childType, entryArray, null, connection)); | |||||
JSONValue entryValue = jsonArray.get(i); | |||||
tokens.add(decodeValue(childType, entryValue, null, connection)); | |||||
} | } | ||||
} | } | ||||
} | } |
package com.vaadin.terminal.gwt.client.communication; | package com.vaadin.terminal.gwt.client.communication; | ||||
import com.google.gwt.core.client.GWT; | import com.google.gwt.core.client.GWT; | ||||
import com.google.gwt.json.client.JSONArray; | |||||
import com.google.gwt.json.client.JSONObject; | import com.google.gwt.json.client.JSONObject; | ||||
import com.google.gwt.json.client.JSONValue; | import com.google.gwt.json.client.JSONValue; | ||||
import com.vaadin.terminal.gwt.client.ApplicationConnection; | import com.vaadin.terminal.gwt.client.ApplicationConnection; | ||||
URLReference reference = GWT.create(URLReference.class); | URLReference reference = GWT.create(URLReference.class); | ||||
JSONObject json = (JSONObject) jsonValue; | JSONObject json = (JSONObject) jsonValue; | ||||
if (json.containsKey("URL")) { | if (json.containsKey("URL")) { | ||||
JSONArray jsonURL = (JSONArray) json.get("URL"); | |||||
JSONValue jsonURL = json.get("URL"); | |||||
String URL = (String) JsonDecoder.decodeValue( | String URL = (String) JsonDecoder.decodeValue( | ||||
new Type(String.class.getCanonicalName(), null), jsonURL, | |||||
null, connection); | |||||
new Type(String.class.getName(), null), jsonURL, null, | |||||
connection); | |||||
reference.setURL(connection.translateVaadinUri(URL)); | reference.setURL(connection.translateVaadinUri(URL)); | ||||
} | } | ||||
return reference; | return reference; |
+ stateType.getName()); | + stateType.getName()); | ||||
} | } | ||||
} | } | ||||
JSONArray stateJsonArray = JsonCodec.encode(state, | |||||
referenceState, stateType, application); | |||||
Object stateJson = JsonCodec.encode(state, referenceState, | |||||
stateType, application); | |||||
sharedStates | |||||
.put(connector.getConnectorId(), stateJsonArray); | |||||
sharedStates.put(connector.getConnectorId(), stateJson); | |||||
} catch (JSONException e) { | } catch (JSONException e) { | ||||
throw new PaintException( | throw new PaintException( | ||||
"Failed to serialize shared state for connector " | "Failed to serialize shared state for connector " |
Iterator<String> it = jsonMap.keys(); | Iterator<String> it = jsonMap.keys(); | ||||
while (it.hasNext()) { | while (it.hasNext()) { | ||||
String key = it.next(); | String key = it.next(); | ||||
Object encodedKey = new JSONTokener(key).nextValue(); | |||||
String keyString = (String) new JSONTokener(key).nextValue(); | |||||
Object encodedKey = new JSONTokener(keyString).nextValue(); | |||||
Object encodedValue = jsonMap.get(key); | Object encodedValue = jsonMap.get(key); | ||||
Object decodedKey = decodeParametrizedType(targetType, | Object decodedKey = decodeParametrizedType(targetType, | ||||
} | } | ||||
} | } | ||||
@Deprecated | |||||
private static JSONArray encode(Object value, Application application) | |||||
throws JSONException { | |||||
return encode(value, null, null, application); | |||||
} | |||||
public static JSONArray encode(Object value, Object referenceValue, | |||||
public static Object encode(Object value, Object referenceValue, | |||||
Type valueType, Application application) throws JSONException { | Type valueType, Application application) throws JSONException { | ||||
if (null == value) { | |||||
return encodeNull(); | |||||
if (valueType == null) { | |||||
throw new IllegalArgumentException("type must be defined"); | |||||
} | } | ||||
if (valueType == null) { | |||||
valueType = value.getClass(); | |||||
if (null == value) { | |||||
return encodeNull(); | |||||
} | } | ||||
String internalTransportType = getInternalTransportType(valueType); | |||||
if (value instanceof String[]) { | if (value instanceof String[]) { | ||||
String[] array = (String[]) value; | String[] array = (String[]) value; | ||||
JSONArray jsonArray = new JSONArray(); | JSONArray jsonArray = new JSONArray(); | ||||
for (int i = 0; i < array.length; ++i) { | for (int i = 0; i < array.length; ++i) { | ||||
jsonArray.put(array[i]); | jsonArray.put(array[i]); | ||||
} | } | ||||
return combineTypeAndValue(JsonEncoder.VTYPE_STRINGARRAY, jsonArray); | |||||
return jsonArray; | |||||
} else if (value instanceof String) { | } else if (value instanceof String) { | ||||
return combineTypeAndValue(JsonEncoder.VTYPE_STRING, value); | |||||
return value; | |||||
} else if (value instanceof Boolean) { | } else if (value instanceof Boolean) { | ||||
return combineTypeAndValue(JsonEncoder.VTYPE_BOOLEAN, value); | |||||
return value; | |||||
} else if (value instanceof Number) { | } else if (value instanceof Number) { | ||||
return combineTypeAndValue(internalTransportType, value); | |||||
return value; | |||||
} else if (value instanceof Collection) { | } else if (value instanceof Collection) { | ||||
if (internalTransportType == null) { | |||||
throw new RuntimeException( | |||||
"Unable to serialize unsupported type: " + valueType); | |||||
} | |||||
Collection<?> collection = (Collection<?>) value; | Collection<?> collection = (Collection<?>) value; | ||||
JSONArray jsonArray = encodeCollection(valueType, collection, | JSONArray jsonArray = encodeCollection(valueType, collection, | ||||
application); | application); | ||||
return combineTypeAndValue(internalTransportType, jsonArray); | |||||
return jsonArray; | |||||
} else if (value instanceof Object[]) { | } else if (value instanceof Object[]) { | ||||
Object[] array = (Object[]) value; | Object[] array = (Object[]) value; | ||||
JSONArray jsonArray = encodeArrayContents(array, application); | JSONArray jsonArray = encodeArrayContents(array, application); | ||||
return combineTypeAndValue(JsonEncoder.VTYPE_ARRAY, jsonArray); | |||||
return jsonArray; | |||||
} else if (value instanceof Map) { | } else if (value instanceof Map) { | ||||
JSONObject jsonMap = encodeMap(valueType, (Map<?, ?>) value, | JSONObject jsonMap = encodeMap(valueType, (Map<?, ?>) value, | ||||
application); | application); | ||||
return combineTypeAndValue(JsonEncoder.VTYPE_MAP, jsonMap); | |||||
return jsonMap; | |||||
} else if (value instanceof Connector) { | } else if (value instanceof Connector) { | ||||
Connector connector = (Connector) value; | Connector connector = (Connector) value; | ||||
if (value instanceof Component | if (value instanceof Component | ||||
.isVisible((Component) value))) { | .isVisible((Component) value))) { | ||||
return encodeNull(); | return encodeNull(); | ||||
} | } | ||||
return combineTypeAndValue(JsonEncoder.VTYPE_CONNECTOR, | |||||
connector.getConnectorId()); | |||||
} else if (internalTransportType != null) { | |||||
return combineTypeAndValue(internalTransportType, | |||||
String.valueOf(value)); | |||||
return connector.getConnectorId(); | |||||
} else if (value instanceof Enum) { | } else if (value instanceof Enum) { | ||||
return encodeEnum((Enum) value, application); | |||||
return encodeEnum((Enum<?>) value, application); | |||||
} else { | } else { | ||||
// Any object that we do not know how to encode we encode by looping | // Any object that we do not know how to encode we encode by looping | ||||
// through fields | // through fields | ||||
return combineTypeAndValue( | |||||
getCustomTransportType((Class<?>) valueType), | |||||
encodeObject(value, referenceValue, application)); | |||||
return encodeObject(value, referenceValue, application); | |||||
} | } | ||||
} | } | ||||
private static JSONArray encodeNull() { | |||||
return combineTypeAndValue(JsonEncoder.VTYPE_NULL, JSONObject.NULL); | |||||
private static Object encodeNull() { | |||||
return JSONObject.NULL; | |||||
} | } | ||||
private static Object encodeObject(Object value, Object referenceValue, | private static Object encodeObject(Object value, Object referenceValue, | ||||
return false; | return false; | ||||
} | } | ||||
private static JSONArray encodeEnum(Enum e, Application application) | |||||
private static String encodeEnum(Enum<?> e, Application application) | |||||
throws JSONException { | throws JSONException { | ||||
String enumIdentifier = e.name(); | |||||
return combineTypeAndValue(e.getClass().getName(), enumIdentifier); | |||||
return e.name(); | |||||
} | } | ||||
private static JSONArray encodeArrayContents(Object[] array, | private static JSONArray encodeArrayContents(Object[] array, | ||||
return jsonArray; | return jsonArray; | ||||
} | } | ||||
private static JSONArray encodeChild(Type targetType, int typeIndex, | |||||
Object o, Application application) throws JSONException { | |||||
private static Object encodeChild(Type targetType, int typeIndex, Object o, | |||||
Application application) throws JSONException { | |||||
if (targetType instanceof ParameterizedType) { | if (targetType instanceof ParameterizedType) { | ||||
Type childType = ((ParameterizedType) targetType) | Type childType = ((ParameterizedType) targetType) | ||||
.getActualTypeArguments()[typeIndex]; | .getActualTypeArguments()[typeIndex]; | ||||
// Encode using the given type | // Encode using the given type | ||||
return encode(o, null, childType, application); | return encode(o, null, childType, application); | ||||
} else { | } else { | ||||
return encode(o, application); | |||||
throw new JSONException("Collection is missing generics"); | |||||
} | } | ||||
} | } | ||||
JSONObject jsonMap = new JSONObject(); | JSONObject jsonMap = new JSONObject(); | ||||
for (Object mapKey : map.keySet()) { | for (Object mapKey : map.keySet()) { | ||||
Object mapValue = map.get(mapKey); | Object mapValue = map.get(mapKey); | ||||
JSONArray encodedKey = encode(mapKey, null, keyType, application); | |||||
JSONArray encodedValue = encode(mapValue, null, valueType, | |||||
application); | |||||
jsonMap.put(encodedKey.toString(), encodedValue); | |||||
Object encodedKey = encode(mapKey, null, keyType, application); | |||||
Object encodedValue = encode(mapValue, null, valueType, application); | |||||
jsonMap.put(JSONObject.quote(encodedKey.toString()), encodedValue); | |||||
} | } | ||||
return jsonMap; | return jsonMap; | ||||
} | } | ||||
private static JSONArray combineTypeAndValue(String type, Object value) { | |||||
if (type == null) { | |||||
throw new RuntimeException("Type for value " + value | |||||
+ " cannot be null!"); | |||||
} | |||||
JSONArray outerArray = new JSONArray(); | |||||
outerArray.put(type); | |||||
outerArray.put(value); | |||||
return outerArray; | |||||
} | |||||
/** | /** | ||||
* Gets the transport type for the given class. Returns null if no transport | * Gets the transport type for the given class. Returns null if no transport | ||||
* type can be found. | * type can be found. |
import com.google.gwt.core.ext.typeinfo.JPrimitiveType; | import com.google.gwt.core.ext.typeinfo.JPrimitiveType; | ||||
import com.google.gwt.core.ext.typeinfo.JType; | import com.google.gwt.core.ext.typeinfo.JType; | ||||
import com.google.gwt.core.ext.typeinfo.TypeOracle; | import com.google.gwt.core.ext.typeinfo.TypeOracle; | ||||
import com.google.gwt.json.client.JSONArray; | |||||
import com.google.gwt.json.client.JSONObject; | import com.google.gwt.json.client.JSONObject; | ||||
import com.google.gwt.json.client.JSONString; | import com.google.gwt.json.client.JSONString; | ||||
import com.google.gwt.json.client.JSONValue; | import com.google.gwt.json.client.JSONValue; | ||||
composer = new ClassSourceFileComposerFactory(serializerPackageName, | composer = new ClassSourceFileComposerFactory(serializerPackageName, | ||||
serializerClassName); | serializerClassName); | ||||
composer.addImport(GWT.class.getName()); | composer.addImport(GWT.class.getName()); | ||||
composer.addImport(JSONArray.class.getName()); | |||||
composer.addImport(JSONValue.class.getName()); | |||||
composer.addImport(com.vaadin.terminal.gwt.client.communication.Type.class | composer.addImport(com.vaadin.terminal.gwt.client.communication.Type.class | ||||
.getName()); | .getName()); | ||||
// composer.addImport(JSONObject.class.getName()); | // composer.addImport(JSONObject.class.getName()); | ||||
+ "\")) {"); | + "\")) {"); | ||||
sourceWriter.indent(); | sourceWriter.indent(); | ||||
String jsonFieldName = "json_" + fieldName; | String jsonFieldName = "json_" + fieldName; | ||||
// JSONArray json_Height = (JSONArray) json.get("height"); | |||||
sourceWriter.println("JSONArray " + jsonFieldName | |||||
+ " = (JSONArray) json.get(\"" + fieldName + "\");"); | |||||
// JSONValue json_Height = json.get("height"); | |||||
sourceWriter.println("JSONValue " + jsonFieldName | |||||
+ " = json.get(\"" + fieldName + "\");"); | |||||
String fieldType; | String fieldType; | ||||
String getterName = "get" + fieldName; | String getterName = "get" + fieldName; |
import junit.framework.TestCase; | import junit.framework.TestCase; | ||||
import com.vaadin.external.json.JSONArray; | |||||
import com.vaadin.terminal.gwt.client.communication.JsonDecoder; | import com.vaadin.terminal.gwt.client.communication.JsonDecoder; | ||||
import com.vaadin.terminal.gwt.client.communication.JsonEncoder; | import com.vaadin.terminal.gwt.client.communication.JsonEncoder; | ||||
import com.vaadin.terminal.gwt.client.ui.splitpanel.AbstractSplitPanelState; | import com.vaadin.terminal.gwt.client.ui.splitpanel.AbstractSplitPanelState; | ||||
stringToStateMap.put("string - state 1", s); | stringToStateMap.put("string - state 1", s); | ||||
stringToStateMap.put("String - state 2", s2); | stringToStateMap.put("String - state 2", s2); | ||||
JSONArray encodedMap = JsonCodec.encode(stringToStateMap, null, | |||||
mapType, null); | |||||
Object encodedMap = JsonCodec.encode(stringToStateMap, null, mapType, | |||||
null); | |||||
ensureDecodedCorrectly(stringToStateMap, encodedMap, mapType); | ensureDecodedCorrectly(stringToStateMap, encodedMap, mapType); | ||||
} | } | ||||
stateToStringMap.put(s, "string - state 1"); | stateToStringMap.put(s, "string - state 1"); | ||||
stateToStringMap.put(s2, "String - state 2"); | stateToStringMap.put(s2, "String - state 2"); | ||||
JSONArray encodedMap = JsonCodec.encode(stateToStringMap, null, | |||||
mapType, null); | |||||
Object encodedMap = JsonCodec.encode(stateToStringMap, null, mapType, | |||||
null); | |||||
ensureDecodedCorrectly(stateToStringMap, encodedMap, mapType); | ensureDecodedCorrectly(stateToStringMap, encodedMap, mapType); | ||||
} | } | ||||
private void ensureDecodedCorrectly(Object original, JSONArray encoded, | |||||
private void ensureDecodedCorrectly(Object original, Object encoded, | |||||
Type type) throws Exception { | Type type) throws Exception { | ||||
Object serverSideDecoded = JsonCodec.decodeInternalOrCustomType(type, | Object serverSideDecoded = JsonCodec.decodeInternalOrCustomType(type, | ||||
encoded, null); | encoded, null); |