From cf925d995b0ba618eaba14c6213f2bdad4efcb8a Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Mon, 19 Mar 2012 15:46:24 +0200 Subject: [PATCH] #8515 Additional fix for sets, and lists from client to server --- .../gwt/client/communication/JsonDecoder.java | 15 ++++ .../gwt/client/communication/JsonEncoder.java | 45 ++++++++-- .../vaadin/terminal/gwt/server/JsonCodec.java | 84 ++++++++++++++----- .../widgetsetutils/SerializerGenerator.java | 5 +- .../SerializerMapGenerator.java | 14 +++- 5 files changed, 132 insertions(+), 31 deletions(-) diff --git a/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java b/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java index 4bc9431d49..86a64cb47c 100644 --- a/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java +++ b/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java @@ -6,9 +6,11 @@ package com.vaadin.terminal.gwt.client.communication; import java.util.ArrayList; 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.core.client.GWT; import com.google.gwt.json.client.JSONArray; @@ -63,6 +65,8 @@ public class JsonDecoder { 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)) { @@ -135,4 +139,15 @@ public class JsonDecoder { } return tokens; } + + private static Set decodeSet(JSONArray jsonArray, + ConnectorMap idMapper, ApplicationConnection connection) { + Set tokens = new HashSet(); + 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, idMapper, connection)); + } + 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 cc8b36dfa4..1215743790 100644 --- a/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java +++ b/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java @@ -4,8 +4,10 @@ package com.vaadin.terminal.gwt.client.communication; +import java.util.Collection; 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.JSONBoolean; @@ -41,6 +43,7 @@ public class JsonEncoder { public static final String VTYPE_STRINGARRAY = "S"; public static final String VTYPE_MAP = "m"; public static final String VTYPE_LIST = "L"; + public static final String VTYPE_SET = "q"; public static final String VTYPE_NULL = "n"; /** @@ -72,13 +75,7 @@ public class JsonEncoder { return combineTypeAndValue(VTYPE_BOOLEAN, JSONBoolean.getInstance((Boolean) value)); } else if (value instanceof Object[]) { - Object[] array = (Object[]) value; - JSONArray jsonArray = new JSONArray(); - for (int i = 0; i < array.length; ++i) { - // TODO handle object graph loops? - jsonArray.set(i, encode(array[i], connectorMap, connection)); - } - return combineTypeAndValue(VTYPE_ARRAY, jsonArray); + return encodeObjectArray((Object[]) value, connectorMap, connection); } else if (value instanceof Map) { Map map = (Map) value; JSONObject jsonMap = new JSONObject(); @@ -92,6 +89,9 @@ public class JsonEncoder { Connector connector = (Connector) value; return combineTypeAndValue(VTYPE_CONNECTOR, new JSONString( connector.getConnectorId())); + } else if (value instanceof Collection) { + return encodeCollection((Collection) value, connectorMap, + connection); } else { String transportType = getTransportType(value); if (transportType != null) { @@ -111,6 +111,35 @@ public class JsonEncoder { } } + private static JSONValue encodeObjectArray(Object[] array, + ConnectorMap connectorMap, ApplicationConnection connection) { + JSONArray jsonArray = new JSONArray(); + for (int i = 0; i < array.length; ++i) { + // TODO handle object graph loops? + jsonArray.set(i, encode(array[i], connectorMap, connection)); + } + return combineTypeAndValue(VTYPE_ARRAY, jsonArray); + } + + private static JSONValue encodeCollection(Collection collection, + ConnectorMap connectorMap, ApplicationConnection connection) { + JSONArray jsonArray = new JSONArray(); + int idx = 0; + for (Object o : collection) { + JSONValue encodedObject = encode(o, connectorMap, connection); + jsonArray.set(idx++, encodedObject); + } + if (collection instanceof Set) { + return combineTypeAndValue(VTYPE_SET, jsonArray); + } else if (collection instanceof List) { + return combineTypeAndValue(VTYPE_LIST, jsonArray); + } else { + throw new RuntimeException("Unsupport collection type: " + + collection.getClass().getName()); + } + + } + private static JSONValue combineTypeAndValue(String type, JSONValue value) { JSONArray outerArray = new JSONArray(); outerArray.set(0, new JSONString(type)); @@ -137,6 +166,8 @@ public class JsonEncoder { return VTYPE_LONG; } else if (value instanceof List) { return VTYPE_LIST; + } else if (value instanceof Set) { + return VTYPE_SET; } 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/server/JsonCodec.java b/src/com/vaadin/terminal/gwt/server/JsonCodec.java index 9fea64a1c7..402d219a70 100644 --- a/src/com/vaadin/terminal/gwt/server/JsonCodec.java +++ b/src/com/vaadin/terminal/gwt/server/JsonCodec.java @@ -11,10 +11,13 @@ import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; 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.vaadin.Application; import com.vaadin.external.json.JSONArray; @@ -38,16 +41,22 @@ public class JsonCodec implements Serializable { registerType(String.class, JsonEncoder.VTYPE_STRING); registerType(Connector.class, JsonEncoder.VTYPE_CONNECTOR); registerType(Boolean.class, JsonEncoder.VTYPE_BOOLEAN); + registerType(boolean.class, JsonEncoder.VTYPE_BOOLEAN); registerType(Integer.class, JsonEncoder.VTYPE_INTEGER); + registerType(int.class, JsonEncoder.VTYPE_INTEGER); registerType(Float.class, JsonEncoder.VTYPE_FLOAT); + registerType(float.class, JsonEncoder.VTYPE_FLOAT); registerType(Double.class, JsonEncoder.VTYPE_DOUBLE); + registerType(double.class, JsonEncoder.VTYPE_FLOAT); registerType(Long.class, JsonEncoder.VTYPE_LONG); + registerType(long.class, JsonEncoder.VTYPE_LONG); // transported as string representation registerType(Enum.class, JsonEncoder.VTYPE_STRING); registerType(String[].class, JsonEncoder.VTYPE_STRINGARRAY); registerType(Object[].class, JsonEncoder.VTYPE_ARRAY); registerType(Map.class, JsonEncoder.VTYPE_MAP); registerType(List.class, JsonEncoder.VTYPE_LIST); + registerType(Set.class, JsonEncoder.VTYPE_SET); } private static void registerType(Class type, String transportType) { @@ -80,6 +89,8 @@ public class JsonCodec implements Serializable { val = decodeArray((JSONArray) value, application); } else if (JsonEncoder.VTYPE_LIST.equals(variableType)) { val = decodeList((JSONArray) value, application); + } else if (JsonEncoder.VTYPE_SET.equals(variableType)) { + val = decodeSet((JSONArray) value, application); } else if (JsonEncoder.VTYPE_MAP.equals(variableType)) { val = decodeMap((JSONObject) value, application); } else if (JsonEncoder.VTYPE_STRINGARRAY.equals(variableType)) { @@ -141,8 +152,8 @@ public class JsonCodec implements Serializable { return list.toArray(new Object[list.size()]); } - private static List decodeList(JSONArray jsonArray, Application application) - throws JSONException { + private static List decodeList(JSONArray jsonArray, + Application application) throws JSONException { List list = new ArrayList(); for (int i = 0; i < jsonArray.length(); ++i) { // each entry always has two elements: type and value @@ -152,6 +163,13 @@ public class JsonCodec implements Serializable { return list; } + private static Set decodeSet(JSONArray jsonArray, + Application application) throws JSONException { + HashSet set = new HashSet(); + set.addAll(decodeList(jsonArray, application)); + return set; + } + /** * Encode a value to a JSON representation for transport from the server to * the client. @@ -174,7 +192,14 @@ public class JsonCodec implements Serializable { if (null == value) { return combineTypeAndValue(JsonEncoder.VTYPE_NULL, JSONObject.NULL); - } else if (value instanceof String[]) { + } + + if (valueType == null) { + valueType = value.getClass(); + } + + String transportType = getTransportType(valueType); + if (value instanceof String[]) { String[] array = (String[]) value; JSONArray jsonArray = new JSONArray(); for (int i = 0; i < array.length; ++i) { @@ -186,11 +211,16 @@ public class JsonCodec implements Serializable { } else if (value instanceof Boolean) { 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, application); - return combineTypeAndValue(JsonEncoder.VTYPE_LIST, jsonArray); + return combineTypeAndValue(transportType, value); + } else if (value instanceof Collection) { + if (transportType == null) { + throw new RuntimeException( + "Unable to serialize unsupported type: " + valueType); + } + Collection collection = (Collection) value; + JSONArray jsonArray = encodeCollection(collection, application); + + return combineTypeAndValue(transportType, jsonArray); } else if (value instanceof Object[]) { Object[] array = (Object[]) value; JSONArray jsonArray = encodeArrayContents(array, application); @@ -203,16 +233,11 @@ public class JsonCodec implements Serializable { Connector connector = (Connector) value; return combineTypeAndValue(JsonEncoder.VTYPE_CONNECTOR, connector.getConnectorId()); - } else if (getTransportType(value) != null) { - return combineTypeAndValue(getTransportType(value), - String.valueOf(value)); + } else if (transportType != null) { + return combineTypeAndValue(transportType, String.valueOf(value)); } else { // Any object that we do not know how to encode we encode by looping // through fields - if (valueType == null) { - valueType = value.getClass(); - } - return combineTypeAndValue(valueType.getCanonicalName(), encodeObject(value, application)); } @@ -290,10 +315,10 @@ public class JsonCodec implements Serializable { return jsonArray; } - private static JSONArray encodeList(List list, Application application) - throws JSONException { + private static JSONArray encodeCollection(Collection collection, + Application application) throws JSONException { JSONArray jsonArray = new JSONArray(); - for (Object o : list) { + for (Object o : collection) { // TODO handle object graph loops? jsonArray.put(encode(o, application)); } @@ -312,6 +337,10 @@ public class JsonCodec implements Serializable { } 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); @@ -326,12 +355,25 @@ public class JsonCodec implements Serializable { * @return * @throws JSONException */ - private static String getTransportType(Object value) throws JSONException { + private static String getTransportType(Object value) { if (null == value) { return JsonEncoder.VTYPE_NULL; } - String transportType = typeToTransportType.get(value.getClass()); - return transportType; + return getTransportType(value.getClass()); + } + + /** + * Gets the transport type for the given class. Returns null if no transport + * type can be found. + * + * @param valueType + * The type that should be transported + * @return + * @throws JSONException + */ + private static String getTransportType(Class valueType) { + return typeToTransportType.get(valueType); + } } diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java index bb05432964..0fe5a38096 100644 --- a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java @@ -230,8 +230,9 @@ public class SerializerGenerator extends Generator { List setterMethods = new ArrayList(); - while (!beanType.getQualifiedSourceName() - .equals(Object.class.getName())) { + while (beanType != null + && !beanType.getQualifiedSourceName().equals( + Object.class.getName())) { for (JMethod method : beanType.getMethods()) { // Process all setters that have corresponding fields if (!method.isPublic() || method.isStatic() diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java index 52b599253f..420c3ae6e7 100644 --- a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java @@ -7,6 +7,7 @@ package com.vaadin.terminal.gwt.widgetsetutils; import java.io.PrintWriter; import java.util.Date; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -199,7 +200,16 @@ public class SerializerMapGenerator extends Generator { continue; } for (JType type : method.getParameterTypes()) { - types.add(type.isClass()); + JClassType t = type.isClass(); + JClassType interfaceType = type.isInterface(); + if (t != null) { + types.add(t); + } else if (interfaceType != null) { + types.add(interfaceType); + } else { + System.err.println("Unknown method parameter type: " + + type.getQualifiedSourceName()); + } } } } @@ -242,6 +252,8 @@ public class SerializerMapGenerator extends Generator { frameworkHandledTypes.add(String[].class); frameworkHandledTypes.add(Object[].class); frameworkHandledTypes.add(Map.class); + frameworkHandledTypes.add(List.class); + frameworkHandledTypes.add(Set.class); } -- 2.39.5