View Javadoc

1   /**
2    * Copyright (C) 2005-2009 Alfresco Software Limited.
3    *
4    * This file is part of the Spring Surf Extension project.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *  http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.springframework.extensions.webscripts.json;
20  
21  import java.util.Iterator;
22  
23  import org.json.JSONException;
24  import org.json.JSONObject;
25  import org.json.JSONStringer;
26  import org.mozilla.javascript.Context;
27  import org.mozilla.javascript.IdScriptableObject;
28  import org.mozilla.javascript.NativeArray;
29  import org.mozilla.javascript.NativeJavaObject;
30  import org.mozilla.javascript.NativeObject;
31  import org.springframework.extensions.surf.exception.WebScriptsPlatformException;
32  
33  /**
34   * Collection of JSON Utility methods.
35   * This class is immutable.
36   * 
37   * @author Roy Wetherall
38   */
39  public class JSONUtils
40  {
41      /**
42       * Converts a given JavaScript native object and converts it to the relevant JSON string.
43       * 
44       * @param object            JavaScript object
45       * @return String           JSON      
46       * @throws JSONException
47       */
48      public String toJSONString(Object object)
49          throws JSONException
50      {
51          JSONStringer json = new JSONStringer();
52  
53          if (object instanceof NativeArray)
54          {
55              nativeArrayToJSONString((NativeArray)object, json);
56          }
57          else if (object instanceof NativeObject)
58          { 
59              nativeObjectToJSONString((NativeObject)object, json);
60          }
61          else
62          {
63              // TODO what else should this support?
64              throw new WebScriptsPlatformException("Only native objects and arrays are currently supported by the toJSONString method.");
65          }        
66          
67          return json.toString();
68      }
69      
70      /**
71       * Takes a JSON string and converts it to a native java script object
72       * 
73       * @param  jsonString       a valid json string
74       * @return NativeObject     the created native JS object that represents the JSON object
75       * @throws JSONException    
76       */
77      public NativeObject toObject(String jsonString)
78          throws JSONException
79      {
80          // TODO deal with json array stirngs
81          
82          // Parse JSON string
83          JSONObject jsonObject = new JSONObject(jsonString);
84          
85          // Create native object 
86          return toObject(jsonObject);
87      }
88      
89      /**
90       * Takes a JSON object and converts it to a native JS object.
91       * 
92       * @param jsonObject        the json object
93       * @return NativeObject     the created native object
94       * @throws JSONException
95       */
96      public NativeObject toObject(JSONObject jsonObject)
97          throws JSONException
98      {
99          // Create native object 
100         NativeObject object = new NativeObject();
101         
102         Iterator<String> keys = jsonObject.keys();
103         while (keys.hasNext())
104         {
105             String key = (String)keys.next();
106             Object value = jsonObject.get(key);
107             if (value instanceof JSONObject)
108             {
109                 object.put(key, object, toObject((JSONObject)value));
110             }
111             else
112             {
113                 object.put(key, object, value);
114             }
115         }
116         
117         return object;
118     }
119     
120     /**
121      * Build a JSON string for a native object
122      * 
123      * @param nativeObject
124      * @param json
125      * @throws JSONException
126      */
127     private void nativeObjectToJSONString(NativeObject nativeObject, JSONStringer json)
128         throws JSONException
129     {
130         json.object();
131         
132         Object[] ids = nativeObject.getIds();
133         for (Object id : ids)
134         {
135             String key = id.toString();
136             json.key(key);
137             
138             Object value = nativeObject.get(key, nativeObject);
139             valueToJSONString(value, json);
140         }
141         
142         json.endObject();
143     }
144     
145     /**
146      * Build JSON string for a native array
147      * 
148      * @param nativeArray
149      * @param json
150      */
151     private void nativeArrayToJSONString(NativeArray nativeArray, JSONStringer json)
152         throws JSONException
153     {
154         Object[] propIds = nativeArray.getIds();
155         if (isArray(propIds) == true)
156         {      
157             json.array();
158             
159             for (int i=0; i<propIds.length; i++)
160             {
161                 Object propId = propIds[i];
162                 if (propId instanceof Integer)
163                 {
164                     Object value = nativeArray.get((Integer)propId, nativeArray);
165                     valueToJSONString(value, json);
166                 }
167             }
168             
169             json.endArray();
170         }
171         else
172         {
173             json.object();
174             
175             for (Object propId : propIds)
176             {
177                 Object value = nativeArray.get(propId.toString(), nativeArray);
178                 json.key(propId.toString());
179                 valueToJSONString(value, json);    
180             }            
181             
182             json.endObject();
183         }
184     }
185     
186     /**
187      * Look at the id's of a native array and try to determine whether it's actually an Array or a HashMap
188      * 
189      * @param ids       id's of the native array
190      * @return boolean  true if it's an array, false otherwise (ie it's a map)
191      */
192     private boolean isArray(Object[] ids)
193     {
194         boolean result = true;
195         for (Object id : ids)
196         {
197             if (id instanceof Integer == false)
198             {
199                result = false;
200                break;
201             }
202         }
203         return result;
204     }
205     
206     /**
207      * Convert value to JSON string
208      * 
209      * @param value
210      * @param json
211      * @throws JSONException
212      */
213     private void valueToJSONString(Object value, JSONStringer json)
214         throws JSONException
215     {
216         if (value instanceof IdScriptableObject &&
217             ((IdScriptableObject)value).getClassName().equals("Date") == true)
218         {
219             // Get the UTC values of the date
220             Object year = NativeObject.callMethod((IdScriptableObject)value, "getUTCFullYear", null);
221             Object month = NativeObject.callMethod((IdScriptableObject)value, "getUTCMonth", null);
222             Object date = NativeObject.callMethod((IdScriptableObject)value, "getUTCDate", null);
223             Object hours = NativeObject.callMethod((IdScriptableObject)value, "getUTCHours", null);
224             Object minutes = NativeObject.callMethod((IdScriptableObject)value, "getUTCMinutes", null);
225             Object seconds = NativeObject.callMethod((IdScriptableObject)value, "getUTCSeconds", null);
226             Object milliSeconds = NativeObject.callMethod((IdScriptableObject)value, "getUTCMilliseconds", null);
227             
228             // Build the JSON object to represent the UTC date
229             json.object()
230                     .key("zone").value("UTC")
231                     .key("year").value(year)
232                     .key("month").value(month)
233                     .key("date").value(date)
234                     .key("hours").value(hours)
235                     .key("minutes").value(minutes)
236                     .key("seconds").value(seconds)
237                     .key("milliseconds").value(milliSeconds)
238                 .endObject();
239             
240         }
241         else if (value instanceof NativeJavaObject)
242         {
243             Object javaValue = Context.jsToJava(value, Object.class);
244             json.value(javaValue);
245         }
246         else if (value instanceof NativeArray)
247         {
248             // Output the native object
249             nativeArrayToJSONString((NativeArray)value, json);
250         }
251         else if (value instanceof NativeObject)
252         {
253             // Output the native array
254             nativeObjectToJSONString((NativeObject)value, json);
255         }
256         else
257         {
258             json.value(value);
259         }
260     }    
261     
262     /**
263      * Encodes a JSON string value
264      * 
265      * @param value     value to encode
266      * @return String   encoded value
267      */
268     public Object encodeJSONString(Object value)
269     {
270         if (value instanceof String)
271         {
272             return JSONWriter.encodeJSONString((String)value);
273         }
274         else
275         {
276             return value;
277         }
278     }
279 }