1616
1717import com .google .common .collect .Lists ;
1818import com .google .visualization .datasource .base .DataSourceParameters ;
19+ import com .google .visualization .datasource .base .OutputType ;
1920import com .google .visualization .datasource .base .ReasonType ;
2021import com .google .visualization .datasource .base .ResponseStatus ;
2122import com .google .visualization .datasource .base .StatusType ;
@@ -61,7 +62,7 @@ private JsonRenderer() {}
6162 * @return a String-form 64-bit hash of this table.
6263 */
6364 public static String getSignature (DataTable data ) {
64- String tableAsString = renderDataTable (data , true , false ).toString ();
65+ String tableAsString = renderDataTable (data , true , false , true ).toString ();
6566 // Casting to long to avoid bug with abs(Integer.MIN_VALUE) being negative.
6667 long longHashCode = tableAsString .hashCode ();
6768 return String .valueOf (Math .abs (longHashCode ));
@@ -78,14 +79,14 @@ public static String getSignature(DataTable data) {
7879 private static String getFaultString (ReasonType reasonType , String description ) {
7980 List <String > objectParts = Lists .newArrayList ();
8081 if (reasonType != null ) {
81- objectParts .add ("reason:'" + reasonType .lowerCaseString () + "' " );
82- objectParts .add ("message:' " + EscapeUtil .jsonEscape (
83- reasonType .getMessageForReasonType (null )) + "' " );
82+ objectParts .add ("\" reason\" : \" " + reasonType .lowerCaseString () + "\" " );
83+ objectParts .add ("\" message\" : \" " + EscapeUtil .jsonEscape (
84+ reasonType .getMessageForReasonType (null )) + "\" " );
8485 }
8586
8687 if (description != null ) {
87- objectParts .add ("detailed_message:' " + EscapeUtil .jsonEscape (description )
88- + "' " );
88+ objectParts .add ("\" detailed_message\" : \" " + EscapeUtil .jsonEscape (description )
89+ + "\" " );
8990 }
9091 return new StrBuilder ("{" ).appendWithSeparators (objectParts , "," ).append ("}" ).toString ();
9192 }
@@ -102,18 +103,18 @@ private static String getFaultString(ReasonType reasonType, String description)
102103 public static CharSequence renderJsonResponse (
103104 DataSourceParameters dsParams ,
104105 ResponseStatus responseStatus ,
105- DataTable data ,
106- boolean isJsonp ) {
106+ DataTable data ) {
107107 StrBuilder sb = new StrBuilder ();
108+ boolean isJsonp = dsParams .getOutputType () == OutputType .JSONP ;
108109 if (isJsonp ) {
109110 sb .append (dsParams .getResponseHandler ()).append ("(" );
110111 }
111- sb .append ("{version:' 0.6' " );
112+ sb .append ("{\" version\" : \" 0.6\" " );
112113
113114 // If no reqId found in the request, do not return reqId in the response.
114115 String requestId = dsParams .getRequestId ();
115116 if (requestId != null ) {
116- sb .append (",reqId:'" ).append (EscapeUtil .jsonEscape (requestId )).append ("' " );
117+ sb .append (",\" reqId\" : \" " ).append (EscapeUtil .jsonEscape (requestId )).append ("\" " );
117118 }
118119
119120 // Check signature.
@@ -128,7 +129,7 @@ public static CharSequence renderJsonResponse(
128129 }
129130
130131 StatusType statusType = responseStatus .getStatusType ();
131- sb .append (",status:'" ).append (statusType .lowerCaseString ()).append ("' " );
132+ sb .append (",\" status\" : \" " ).append (statusType .lowerCaseString ()).append ("\" " );
132133
133134 // There are reason and messages if the status is WARNING/ERROR.
134135 if (statusType != StatusType .OK ) {
@@ -141,10 +142,10 @@ public static CharSequence renderJsonResponse(
141142 warningJsonStrings .add (getFaultString (warning .getReasonType (), warning .getMessage ()));
142143 }
143144 }
144- sb .append (",warnings:[" ).appendWithSeparators (warningJsonStrings , "," ).append ("]" );
145+ sb .append (",\" warnings\" :[" ).appendWithSeparators (warningJsonStrings , "," ).append ("]" );
145146
146147 } else { // Status is error.
147- sb .append (",errors:[" );
148+ sb .append (",\" errors\" :[" );
148149 sb .append (getFaultString (responseStatus .getReasonType (), responseStatus .getDescription ()));
149150 sb .append ("]" );
150151 }
@@ -153,8 +154,8 @@ public static CharSequence renderJsonResponse(
153154 if ((statusType != StatusType .ERROR ) && (data != null )) {
154155 // MessageType OK or WARNING,
155156 // so need to attach a data table (and a signature).
156- sb .append (",sig:'" ).append (JsonRenderer .getSignature (data )).append ("' " );
157- sb .append (",table:" ).append (JsonRenderer .renderDataTable (data , true , true ));
157+ sb .append (",\" sig\" : \" " ).append (JsonRenderer .getSignature (data )).append ("\" " );
158+ sb .append (",\" table\" :" ).append (JsonRenderer .renderDataTable (data , true , true , isJsonp ));
158159 }
159160
160161 sb .append ("}" );
@@ -172,11 +173,18 @@ public static CharSequence renderJsonResponse(
172173 * but without the data rows.
173174 * @param includeFormatting False if formatting information should be omitted from the
174175 * generated json.
175- *
176+ * @param renderDateAsDateConstructor True -> date constructor, False -> date string.
177+ * True if date values should be rendered into the json string as a call to
178+ * Date object constructor (usually used when rendering jsonp string).
179+ * False if it should should be rendered as string.
180+ * For example, when rendering the date 1/1/2011 as Date object constructor its value
181+ * in the json string will be new Date(2011,1,1), and when rendered as string
182+ * will be "Date(2011,1,1)"
183+ *
176184 * @return The char sequence with the Json string.
177185 */
178186 public static CharSequence renderDataTable (DataTable dataTable , boolean includeValues ,
179- boolean includeFormatting ) {
187+ boolean includeFormatting , boolean renderDateAsDateConstructor ) {
180188 if (dataTable .getColumnDescriptions ().isEmpty ()) {
181189 return "" ;
182190 }
@@ -185,7 +193,7 @@ public static CharSequence renderDataTable(DataTable dataTable, boolean includeV
185193
186194 StringBuilder sb = new StringBuilder ();
187195 sb .append ("{" );
188- sb .append ("cols:[" ); // column descriptions.
196+ sb .append ("\" cols\" :[" ); // column descriptions.
189197
190198 ColumnDescription col ;
191199 for (int colId = 0 ; colId < columnDescriptions .size (); colId ++) {
@@ -198,7 +206,7 @@ public static CharSequence renderDataTable(DataTable dataTable, boolean includeV
198206 sb .append ("]" ); // columns.
199207
200208 if (includeValues ) {
201- sb .append (",rows:[" );
209+ sb .append (",\" rows\" :[" );
202210 List <TableCell > cells ;
203211 TableCell cell ;
204212 ColumnDescription columnDescription ;
@@ -207,23 +215,23 @@ public static CharSequence renderDataTable(DataTable dataTable, boolean includeV
207215 for (int rowId = 0 ; rowId < rows .size (); rowId ++) {
208216 TableRow tableRow = rows .get (rowId );
209217 cells = tableRow .getCells ();
210- sb .append ("{c :[" );
218+ sb .append ("{\" c \" :[" );
211219 for (int cellId = 0 ; cellId < cells .size (); cellId ++) {
212220 cell = cells .get (cellId );
213221 if (cellId < (cells .size () - 1 )) {
214- appendCellJson (cell , sb , includeFormatting , false );
222+ appendCellJson (cell , sb , includeFormatting , false , renderDateAsDateConstructor );
215223 sb .append ("," );
216224 } else {
217225 // Last column in the row.
218- appendCellJson (cell , sb , includeFormatting , true );
226+ appendCellJson (cell , sb , includeFormatting , true , renderDateAsDateConstructor );
219227 }
220228 }
221229 sb .append ("]" );
222230
223231 // Row properties.
224232 String customPropertiesString = getPropertiesMapString (tableRow .getCustomProperties ());
225233 if (customPropertiesString != null ) {
226- sb .append (",p :" ).append (customPropertiesString );
234+ sb .append (",\" p \" :" ).append (customPropertiesString );
227235 }
228236
229237 sb .append ("}" ); // cells.
@@ -238,7 +246,7 @@ public static CharSequence renderDataTable(DataTable dataTable, boolean includeV
238246 // Table properties.
239247 String customPropertiesString = getPropertiesMapString (dataTable .getCustomProperties ());
240248 if (customPropertiesString != null ) {
241- sb .append (",p :" ).append (customPropertiesString );
249+ sb .append (",\" p \" :" ).append (customPropertiesString );
242250 }
243251
244252 sb .append ("}" ); // table.
@@ -252,11 +260,19 @@ public static CharSequence renderDataTable(DataTable dataTable, boolean includeV
252260 * @param sb The string buffer to append to.
253261 * @param includeFormatting Flase if formatting information should be omitted from the json.
254262 * @param isLastColumn Is this the last column in the row.
263+ * @param renderDateAsDateConstructor True -> date constructor, False -> date string.
264+ * True if date values should be rendered into the json string as a call to
265+ * Date object constructor (usually used when rendering jsonp string).
266+ * False if it should should be rendered as string.
267+ * For example, when rendering the date 1/1/2011 as Date object constructor its value
268+ * in the json string will be new Date(2011,1,1), and when rendered as string
269+ * will be "Date(2011,1,1)"
255270 *
256271 * @return The input string builder.
257272 */
258273 public static StringBuilder appendCellJson (TableCell cell ,
259- StringBuilder sb , boolean includeFormatting , boolean isLastColumn ) {
274+ StringBuilder sb , boolean includeFormatting , boolean isLastColumn ,
275+ boolean renderDateAsDateConstructor ) {
260276 Value value = cell .getValue ();
261277 ValueType type = cell .getType ();
262278 StringBuilder valueJson = new StringBuilder ();
@@ -276,20 +292,28 @@ public static StringBuilder appendCellJson(TableCell cell,
276292 valueJson .append (((BooleanValue ) value ).getValue ());
277293 break ;
278294 case DATE :
279- valueJson .append ("new Date(" );
295+ valueJson .append ("Date(" );
280296 dateValue = (DateValue ) value ;
281297 valueJson .append (dateValue .getYear ()).append ("," );
282298 valueJson .append (dateValue .getMonth ()).append ("," );
283299 valueJson .append (dateValue .getDayOfMonth ());
284300 valueJson .append (")" );
301+ if (renderDateAsDateConstructor ) {
302+ // Rendering date as a call to Date constructor, e.g new Date(2011,1,1)
303+ valueJson .insert (0 , "new " );
304+ } else {
305+ // Rendering date in string format, e.g "Date(2011,1,1)"
306+ valueJson .insert (0 , "\" " );
307+ valueJson .append ("\" " );
308+ }
285309 break ;
286310 case NUMBER :
287311 valueJson .append (((NumberValue ) value ).getValue ());
288312 break ;
289313 case TEXT :
290- valueJson .append ("' " );
314+ valueJson .append ("\" " );
291315 valueJson .append (EscapeUtil .jsonEscape (value .toString ()));
292- valueJson .append ("' " );
316+ valueJson .append ("\" " );
293317 break ;
294318 case TIMEOFDAY :
295319 valueJson .append ("[" );
@@ -302,7 +326,7 @@ public static StringBuilder appendCellJson(TableCell cell,
302326 break ;
303327 case DATETIME :
304328 calendar = ((DateTimeValue ) value ).getCalendar ();
305- valueJson .append ("new Date(" );
329+ valueJson .append ("Date(" );
306330 valueJson .append (calendar .get (GregorianCalendar .YEAR )).append ("," );
307331 valueJson .append (calendar .get (GregorianCalendar .MONTH )).append ("," );
308332 valueJson .append (calendar .get (GregorianCalendar .DAY_OF_MONTH ));
@@ -312,6 +336,14 @@ public static StringBuilder appendCellJson(TableCell cell,
312336 valueJson .append (calendar .get (GregorianCalendar .MINUTE )).append ("," );
313337 valueJson .append (calendar .get (GregorianCalendar .SECOND ));
314338 valueJson .append (")" );
339+ if (renderDateAsDateConstructor ) {
340+ // Rendering date as a call to Date constructor, e.g new Date(2011,1,1,0,0,0)
341+ valueJson .insert (0 , "new " );
342+ } else {
343+ // Rendering date in string format, e.g "Date(2011,1,1,0,0,0)"
344+ valueJson .insert (0 , "\" " );
345+ valueJson .append ("\" " );
346+ }
315347 break ;
316348 default :
317349 throw new IllegalArgumentException ("Illegal value Type " + type );
@@ -335,14 +367,14 @@ public static StringBuilder appendCellJson(TableCell cell,
335367 if ((isLastColumn ) || (!isJsonNull )) {
336368 sb .append ("{" );
337369 // Value
338- sb .append ("v :" ).append (valueJson );
370+ sb .append ("\" v \" :" ).append (valueJson );
339371 // Formatted value
340372 if ((includeFormatting ) && (!escapedFormattedString .equals ("" ))) {
341- sb .append (",f:'" ).append (escapedFormattedString ).append ("' " );
373+ sb .append (",\" f \" : \" " ).append (escapedFormattedString ).append ("\" " );
342374 }
343375 String customPropertiesString = getPropertiesMapString (cell .getCustomProperties ());
344376 if (customPropertiesString != null ) {
345- sb .append (",p :" ).append (customPropertiesString );
377+ sb .append (",\" p \" :" ).append (customPropertiesString );
346378 }
347379 sb .append ("}" );
348380 }
@@ -360,14 +392,14 @@ public static StringBuilder appendCellJson(TableCell cell,
360392 public static StringBuilder appendColumnDescriptionJson (
361393 ColumnDescription col , StringBuilder sb ) {
362394 sb .append ("{" );
363- sb .append ("id:'" ).append (EscapeUtil .jsonEscape (col .getId ())).append ("' ," );
364- sb .append ("label:'" ).append (EscapeUtil .jsonEscape (col .getLabel ())).append ("' ," );
365- sb .append ("type:'" ).append (col .getType ().getTypeCodeLowerCase ()).append ("' ," );
366- sb .append ("pattern:'" ).append (EscapeUtil .jsonEscape (col .getPattern ())).append ("' " );
395+ sb .append ("\" id \" : \" " ).append (EscapeUtil .jsonEscape (col .getId ())).append ("\" ," );
396+ sb .append ("\" label\" : \" " ).append (EscapeUtil .jsonEscape (col .getLabel ())).append ("\" ," );
397+ sb .append ("\" type\" : \" " ).append (col .getType ().getTypeCodeLowerCase ()).append ("\" ," );
398+ sb .append ("\" pattern\" : \" " ).append (EscapeUtil .jsonEscape (col .getPattern ())).append ("\" " );
367399
368400 String customPropertiesString = getPropertiesMapString (col .getCustomProperties ());
369401 if (customPropertiesString != null ) {
370- sb .append (",p :" ).append (customPropertiesString );
402+ sb .append (",\" p \" :" ).append (customPropertiesString );
371403 }
372404
373405 sb .append ("}" );
@@ -386,9 +418,9 @@ private static String getPropertiesMapString(Map<String, String> propertiesMap)
386418 if ((propertiesMap != null ) && (!propertiesMap .isEmpty ())) {
387419 List <String > customPropertiesStrings = Lists .newArrayList ();
388420 for (Map .Entry <String , String > entry : propertiesMap .entrySet ()) {
389- customPropertiesStrings .add ("' "
390- + EscapeUtil .jsonEscape (entry .getKey ()) + "':' "
391- + EscapeUtil .jsonEscape (entry .getValue ()) + "' " );
421+ customPropertiesStrings .add ("\" "
422+ + EscapeUtil .jsonEscape (entry .getKey ()) + "\" : \" "
423+ + EscapeUtil .jsonEscape (entry .getValue ()) + "\" " );
392424 }
393425 customPropertiesString = new StrBuilder ("{" )
394426 .appendWithSeparators (customPropertiesStrings , "," ).append ("}" ).toString ();
0 commit comments