6cb7cb5ccc977a9e0d679a2668614cbb6ec3ed5c
[jalview.git] / src / jalview / javascript / json / JSON.java
1 package jalview.javascript.json;
2
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.Reader;
7 import java.net.URL;
8 import java.util.ArrayList;
9 import java.util.Hashtable;
10 import java.util.Iterator;
11 import java.util.List;
12
13 /**
14  * 
15  * A rudimentary JSON converter/iterator that uses the browser's native AJAX
16  * json data type delivery mechanism.
17  * 
18  * Arrays are delivered as ArrayList<Object> where Object may be Boolean,
19  * String, Long, Double, ArrayList, and "Map-like object".
20  * 
21  * For speed, the maps returned are just JavaScript maps with a few added
22  * methods for extracting data. [get(), contains(), probably should add keySet,
23  * valueSet, and entrySet].
24  * 
25  * @author hansonr Bob Hanson St. Olaf College 1/24/2019
26  *
27  */
28 public class JSON {
29
30         /**
31          * A privately initialized class that allows us to do the object
32          * conversion from JavaScript to "Java" on the fly. 
33          * 
34          * @author hansonr
35          *
36          */
37         @SuppressWarnings("serial")
38         public static class JSONList extends ArrayList<Object>  {
39
40
41                 static ListIterator iter;
42                 
43                 JSONList(Object[] a) {
44                         super();
45                         /**
46                          * @j2sNative
47                          * 
48                          * this.elementData = a;
49                          * this.size = a.length;
50                          */
51                 }
52                 
53                 public Object get(int i) {
54                         Object o = null;
55                         /**
56                          * @j2sNative
57                          * 
58                          *  o = this.elementData[i]; 
59                          *  
60                          */
61                         return JSON.toObject(o);
62                 }
63
64
65                 @Override
66                 public Iterator<Object> iterator() {
67                         if (iter == null)
68                                 iter = new ListIterator();
69                         iter.pt = 0;
70                         iter.list = this;
71                         return iter;
72                 }
73
74                 
75                 /**
76                  * 
77                  * @author hansonr
78                  *
79                  */
80                 public static class ListIterator implements Iterator<Object> {
81
82                         ListIterator() {/* restricted */}
83                         
84                         public JSONList list;
85                         int pt = -1;
86
87                         @Override
88                         public boolean hasNext() {
89                                 @SuppressWarnings("unused")
90                                 boolean more;
91                                 /**
92                                  * @j2sNative
93                                  * 
94                                  * more = this.list && (this.pt < this.list.size);
95                                  * if (!more) {
96                                  *   this.list = null;
97                                  *   this.pt = -1;
98                                  * }
99                                  * return more; 
100                                  */
101                                 {
102                                 return pt < list.size();
103                                 }
104                         }
105
106                         @Override
107                         public Object next() {
108                                 Object o = null;
109                                 /**
110                                  * @j2sNative o = this.list.elementData[this.pt++];
111                                  * 
112                                  */
113                                 
114                                 return toObject(o);                             
115                         }
116                 }
117         }
118
119         /**
120          * A simple encoding of sequential key/value pairs for a jQuery.ajax call. If
121          * the first key is "url" and the second is an object, then the ajax object is
122          * attached to that url as well, just for transport purposes within the system.
123          * 
124          * @param keyValues assumed to be simple String,Object pairs. String objects
125          *                  will be surrounded by double quotes.
126          */
127         public static Object setAjax(Object... keyValues) {
128                 Object ajax = null;
129                 /**
130                  * @j2sNative ajax = {}; if (keyValues[0] == "url" && typeof keyValues[1] ==
131                  *            "object") { ajax = keyValues[1].ajax || (keyValues[1].ajax = ajax); }
132                  * 
133                  *            for (var i = 0; i < keyValues.length;) { var key = keyValues[i++];
134                  *            var val = keyValues[i++]; ajax[key] = val; }
135                  */
136                 return ajax;
137         }
138
139         public static void setAjax(URL url) {
140                 setAjax("url", url, "dataType", "json", "async", Boolean.FALSE);        
141         }
142
143         public static BufferedReader getJSONReader(InputStream is) {
144                 return new JSONReader(is);
145         }
146
147         public static class JSONReader extends BufferedReader {
148                 Object data;
149
150                 public JSONReader(InputStream in) {
151                         super((Reader) (Object) in);
152                         // could be buffered
153                         data = toObject(/** @j2sNative $in._ajaxData || $in.$in && $in.$in._ajaxData || */ null);
154                         
155                 }
156
157                 public JSONReader(Reader in) {
158                         super(in);
159                         // could be buffered
160                         data = toObject(/** @j2sNative $in._ajaxData || $in.$in && $in.$in._ajaxData || */ null);
161                 }
162
163                 public JSONReader(String json) {
164                         super((Reader) (Object) "");
165                         data = toObject(/** @j2sNative  swingjs.JSUtil.parseJSON$S(json)|| */null); 
166                 }
167
168                 @Override
169                 public void close() {
170                         data = null;
171                         try {
172                                 super.close();
173                         } catch (IOException e) {
174                                 // ignore, especially if we set $in to a string!
175                         }
176                 }
177         }
178
179         @SuppressWarnings("resource")
180         public static Object parse(String json) {
181                 return new JSONReader(json).data;
182         }
183
184         public static Object parse(Reader br) {
185                 return ((JSONReader) br).data;
186         }
187
188         /**
189          * Get an object in the JSON associative array.
190          * @param br
191          * @param key
192          * @return
193          */
194         @SuppressWarnings("unused")
195         public static Object toObject(Object o) {
196                 if (o == null)
197                         return null;
198                 String type = /** @j2sNative (typeof o) + */"";
199                 switch (type) {
200                 case "string":
201                         return o;
202                 case "number":
203                         double n = 0;
204                         if (/** @j2sNative (n = o) == (n|0) || */false)
205                                 return Long.valueOf((long) n);
206                         return Double.valueOf(n);
207                 case "boolean":
208                         return Boolean.valueOf(/** @j2sNative !!o || */false);
209                 case "object":
210                         boolean isArray =  /** @j2sNative o instanceof Array || */false;
211                         if (isArray) {
212                                 return toList((Object[]) o);
213                         }
214                         return toMap(o);
215                 default:
216                         return o;
217                 }
218         }
219         
220         Object get(String key) {
221                 /**
222                  * @j2sNative
223                  * 
224                  *  return C$.toObject$O(this[key]);
225                  */
226                 {
227                         return null;
228                 }
229         }
230         boolean contains(String key) {
231                 /**
232                  * @j2sNative
233                  * 
234                  *  return typeof this[key] != "undefined"
235                  */
236                 {
237                         return false;
238                 }
239         }
240         
241         @SuppressWarnings("unchecked")
242         private static Hashtable<String, Object> toMap(Object map) {
243                 /**
244                  * @j2sNative
245                  * map.get$O = C$.prototype.get$S;
246                  * map.contains$O = C$.prototype.contains$S;
247                  */                     
248                 return (Hashtable<String, Object>) map;
249         }
250
251         private static List<Object> toList(Object[] a) {
252                 return new JSONList(a);
253         }
254
255 }