You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

JsonEncoder.java 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /*
  2. @VaadinApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.terminal.gwt.client.communication;
  5. import java.util.Collection;
  6. import java.util.List;
  7. import java.util.Map;
  8. import java.util.Set;
  9. import com.google.gwt.json.client.JSONArray;
  10. import com.google.gwt.json.client.JSONBoolean;
  11. import com.google.gwt.json.client.JSONNull;
  12. import com.google.gwt.json.client.JSONObject;
  13. import com.google.gwt.json.client.JSONString;
  14. import com.google.gwt.json.client.JSONValue;
  15. import com.vaadin.terminal.gwt.client.ApplicationConnection;
  16. import com.vaadin.terminal.gwt.client.Connector;
  17. import com.vaadin.terminal.gwt.client.ConnectorMap;
  18. /**
  19. * Encoder for converting RPC parameters and other values to JSON for transfer
  20. * between the client and the server.
  21. *
  22. * Currently, basic data types as well as Map, String[] and Object[] are
  23. * supported, where maps and Object[] can contain other supported data types.
  24. *
  25. * TODO extensible type support
  26. *
  27. * @since 7.0
  28. */
  29. public class JsonEncoder {
  30. public static final String VTYPE_CONNECTOR = "c";
  31. public static final String VTYPE_BOOLEAN = "b";
  32. public static final String VTYPE_DOUBLE = "d";
  33. public static final String VTYPE_FLOAT = "f";
  34. public static final String VTYPE_LONG = "l";
  35. public static final String VTYPE_INTEGER = "i";
  36. public static final String VTYPE_STRING = "s";
  37. public static final String VTYPE_ARRAY = "a";
  38. public static final String VTYPE_STRINGARRAY = "S";
  39. public static final String VTYPE_MAP = "m";
  40. public static final String VTYPE_LIST = "L";
  41. public static final String VTYPE_SET = "q";
  42. public static final String VTYPE_NULL = "n";
  43. /**
  44. * Encode a value to a JSON representation for transport from the client to
  45. * the server.
  46. *
  47. * @param value
  48. * value to convert
  49. * @param connectorMap
  50. * mapper from connectors to connector IDs
  51. * @param connection
  52. * @return JSON representation of the value
  53. */
  54. public static JSONValue encode(Object value, ConnectorMap connectorMap,
  55. ApplicationConnection connection) {
  56. if (null == value) {
  57. return combineTypeAndValue(VTYPE_NULL, JSONNull.getInstance());
  58. } else if (value instanceof String[]) {
  59. String[] array = (String[]) value;
  60. JSONArray jsonArray = new JSONArray();
  61. for (int i = 0; i < array.length; ++i) {
  62. jsonArray.set(i, new JSONString(array[i]));
  63. }
  64. return combineTypeAndValue(VTYPE_STRINGARRAY, jsonArray);
  65. } else if (value instanceof String) {
  66. return combineTypeAndValue(VTYPE_STRING, new JSONString(
  67. (String) value));
  68. } else if (value instanceof Boolean) {
  69. return combineTypeAndValue(VTYPE_BOOLEAN,
  70. JSONBoolean.getInstance((Boolean) value));
  71. } else if (value instanceof Object[]) {
  72. return encodeObjectArray((Object[]) value, connectorMap, connection);
  73. } else if (value instanceof Map) {
  74. Map<String, Object> map = (Map<String, Object>) value;
  75. JSONObject jsonMap = new JSONObject();
  76. for (String mapKey : map.keySet()) {
  77. // TODO handle object graph loops?
  78. Object mapValue = map.get(mapKey);
  79. jsonMap.put(mapKey, encode(mapValue, connectorMap, connection));
  80. }
  81. return combineTypeAndValue(VTYPE_MAP, jsonMap);
  82. } else if (value instanceof Connector) {
  83. Connector connector = (Connector) value;
  84. return combineTypeAndValue(VTYPE_CONNECTOR, new JSONString(
  85. connector.getConnectorId()));
  86. } else if (value instanceof Collection) {
  87. return encodeCollection((Collection) value, connectorMap,
  88. connection);
  89. } else {
  90. String transportType = getTransportType(value);
  91. if (transportType != null) {
  92. return combineTypeAndValue(transportType,
  93. new JSONString(String.valueOf(value)));
  94. } else {
  95. // Try to find a generated serializer object, class name is the
  96. // type
  97. transportType = value.getClass().getName();
  98. JSONSerializer serializer = JsonDecoder.serializerMap
  99. .getSerializer(transportType);
  100. // TODO handle case with no serializer found
  101. return combineTypeAndValue(transportType,
  102. serializer.serialize(value, connectorMap, connection));
  103. }
  104. }
  105. }
  106. private static JSONValue encodeObjectArray(Object[] array,
  107. ConnectorMap connectorMap, ApplicationConnection connection) {
  108. JSONArray jsonArray = new JSONArray();
  109. for (int i = 0; i < array.length; ++i) {
  110. // TODO handle object graph loops?
  111. jsonArray.set(i, encode(array[i], connectorMap, connection));
  112. }
  113. return combineTypeAndValue(VTYPE_ARRAY, jsonArray);
  114. }
  115. private static JSONValue encodeCollection(Collection collection,
  116. ConnectorMap connectorMap, ApplicationConnection connection) {
  117. JSONArray jsonArray = new JSONArray();
  118. int idx = 0;
  119. for (Object o : collection) {
  120. JSONValue encodedObject = encode(o, connectorMap, connection);
  121. jsonArray.set(idx++, encodedObject);
  122. }
  123. if (collection instanceof Set) {
  124. return combineTypeAndValue(VTYPE_SET, jsonArray);
  125. } else if (collection instanceof List) {
  126. return combineTypeAndValue(VTYPE_LIST, jsonArray);
  127. } else {
  128. throw new RuntimeException("Unsupport collection type: "
  129. + collection.getClass().getName());
  130. }
  131. }
  132. private static JSONValue combineTypeAndValue(String type, JSONValue value) {
  133. JSONArray outerArray = new JSONArray();
  134. outerArray.set(0, new JSONString(type));
  135. outerArray.set(1, value);
  136. return outerArray;
  137. }
  138. private static String getTransportType(Object value) {
  139. if (value == null) {
  140. return VTYPE_NULL;
  141. } else if (value instanceof String) {
  142. return VTYPE_STRING;
  143. } else if (value instanceof Connector) {
  144. return VTYPE_CONNECTOR;
  145. } else if (value instanceof Boolean) {
  146. return VTYPE_BOOLEAN;
  147. } else if (value instanceof Integer) {
  148. return VTYPE_INTEGER;
  149. } else if (value instanceof Float) {
  150. return VTYPE_FLOAT;
  151. } else if (value instanceof Double) {
  152. return VTYPE_DOUBLE;
  153. } else if (value instanceof Long) {
  154. return VTYPE_LONG;
  155. } else if (value instanceof List) {
  156. return VTYPE_LIST;
  157. } else if (value instanceof Set) {
  158. return VTYPE_SET;
  159. } else if (value instanceof Enum) {
  160. return VTYPE_STRING; // transported as string representation
  161. } else if (value instanceof String[]) {
  162. return VTYPE_STRINGARRAY;
  163. } else if (value instanceof Object[]) {
  164. return VTYPE_ARRAY;
  165. } else if (value instanceof Map) {
  166. return VTYPE_MAP;
  167. }
  168. return null;
  169. }
  170. }