added JSON reading ability, including serializable objects
[OpenSRF.git] / src / java / org / opensrf / util / JSONReader.java
1 package org.opensrf.util;
2
3 import java.io.*;
4 import java.util.*;
5
6 import org.json.JSONTokener;
7 import org.json.JSONObject;
8 import org.json.JSONArray;
9
10
11 /**
12  * JSON utilities.
13  */
14 public class JSONReader {
15
16     /** Special OpenSRF serializable object netClass key */
17     public static final String JSON_CLASS_KEY = "__c";
18
19     /** Special OpenSRF serializable object payload key */
20     public static final String JSON_PAYLOAD_KEY = "__p";
21
22     private String json;
23
24     public JSONReader(String json) {
25         this.json = json;
26     }
27
28     /**
29      * Parses JSON and creates an object.
30      * @param json The JSON string to parse
31      * @return The resulting object which may be a List, 
32      * Map, Number, String, Boolean, or null
33      */
34     public Object read() throws JSONException {
35         JSONTokener tk = new JSONTokener(json);
36         try {
37             return readSubObject(tk.nextValue());
38         } catch(org.json.JSONException e) {
39             throw new JSONException(e.toString());
40         }
41     }
42
43     public List<?> readArray() throws JSONException {
44         Object o = read();
45         try {
46             return (List<?>) o;
47         } catch(Exception e) {
48             throw new JSONException("readArray(): JSON cast exception");
49         }
50     }
51
52     public Map<?,?> readObject() throws JSONException {
53         Object o = read();
54         try {
55             return (Map<?,?>) o;
56         } catch(Exception e) {
57             throw new JSONException("readObject(): JSON cast exception");
58         }
59     }
60
61
62     private Object readSubObject(Object obj) throws JSONException {
63
64         if( obj == null || 
65             obj instanceof String || 
66             obj instanceof Number ||
67             obj instanceof Boolean)
68                 return obj;
69
70         try {
71
72             if( obj instanceof JSONObject ) {
73
74                 /* read objects */
75                 String key;
76                 JSONObject jobj = (JSONObject) obj;
77                 Map<String, Object> map = new HashMap<String, Object>();
78
79                 for( Iterator e = jobj.keys(); e.hasNext(); ) {
80                     key = (String) e.next();
81
82                     /* we encoutered the special class key */
83                     if( JSON_CLASS_KEY.equals(key) ) 
84                         return buildRegisteredObject(
85                             (String) jobj.get(key), jobj.get(JSON_PAYLOAD_KEY));
86
87                     /* we encountered the data key */
88                     if( JSON_PAYLOAD_KEY.equals(key) ) 
89                         return buildRegisteredObject(
90                             (String) jobj.get(JSON_CLASS_KEY), jobj.get(key));
91
92                     map.put(key, readSubObject(jobj.get(key)));
93                 }
94                 return map;
95             } 
96             
97             if ( obj instanceof JSONArray ) {
98
99                 JSONArray jarr = (JSONArray) obj;
100                 int length = jarr.length();
101                 List<Object> list = new ArrayList<Object>(length);
102
103                 for( int i = 0; i < length; i++ ) 
104                     list.add(readSubObject(jarr.get(i)));   
105                 return list;
106                 
107             }
108
109         } catch(org.json.JSONException e) {
110
111             throw new JSONException(e.toString());
112         }
113
114         return null;
115     }
116
117
118
119     /**
120      * Builds an OSRFObject map registered OSRFHash object based on the JSON object data.
121      * @param netClass The network class hint for this object.
122      * @param paylaod The actual object on the wire.
123      */
124     private OSRFObject buildRegisteredObject(
125         String netClass, Object payload) throws JSONException {
126
127         OSRFRegistry registry = OSRFRegistry.getRegistry(netClass);
128         OSRFObject obj = new OSRFObject(registry);
129
130         try {
131             if( payload instanceof JSONArray ) {
132                 JSONArray jarr = (JSONArray) payload;
133
134                 /* for each array item, instert the item into the hash.  the hash 
135                  * key is found by extracting the fields array from the registered 
136                  * object at the current array index */
137                 String fields[] = registry.getFields();
138                 for( int i = 0; i < jarr.length(); i++ ) {
139                     obj.put(fields[i], readSubObject(jarr.get(i)));   
140                 }
141
142             } else if( payload instanceof JSONObject ) {
143
144                 /* since this is a hash, simply copy the data over */
145                 JSONObject jobj = (JSONObject) payload;
146                 String key;
147                 for( Iterator e = jobj.keys(); e.hasNext(); ) {
148                     key = (String) e.next();
149                     obj.put(key, readSubObject(jobj.get(key)));
150                 }
151             }
152
153         } catch(org.json.JSONException e) {
154             throw new JSONException(e.toString());
155         }
156
157         return obj;
158     }
159 }
160
161
162