From 6f1a50917d60504ae3eb46377d3020271accacaf Mon Sep 17 00:00:00 2001 From: hansonr Date: Fri, 25 Jan 2019 03:23:54 -0600 Subject: [PATCH] JavaScript browser-based JSON parsing --- src/jalview/javascript/json/JSON.java | 255 +++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 src/jalview/javascript/json/JSON.java diff --git a/src/jalview/javascript/json/JSON.java b/src/jalview/javascript/json/JSON.java new file mode 100644 index 0000000..6cb7cb5 --- /dev/null +++ b/src/jalview/javascript/json/JSON.java @@ -0,0 +1,255 @@ +package jalview.javascript.json; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.net.URL; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; + +/** + * + * A rudimentary JSON converter/iterator that uses the browser's native AJAX + * json data type delivery mechanism. + * + * Arrays are delivered as ArrayList where Object may be Boolean, + * String, Long, Double, ArrayList, and "Map-like object". + * + * For speed, the maps returned are just JavaScript maps with a few added + * methods for extracting data. [get(), contains(), probably should add keySet, + * valueSet, and entrySet]. + * + * @author hansonr Bob Hanson St. Olaf College 1/24/2019 + * + */ +public class JSON { + + /** + * A privately initialized class that allows us to do the object + * conversion from JavaScript to "Java" on the fly. + * + * @author hansonr + * + */ + @SuppressWarnings("serial") + public static class JSONList extends ArrayList { + + + static ListIterator iter; + + JSONList(Object[] a) { + super(); + /** + * @j2sNative + * + * this.elementData = a; + * this.size = a.length; + */ + } + + public Object get(int i) { + Object o = null; + /** + * @j2sNative + * + * o = this.elementData[i]; + * + */ + return JSON.toObject(o); + } + + + @Override + public Iterator iterator() { + if (iter == null) + iter = new ListIterator(); + iter.pt = 0; + iter.list = this; + return iter; + } + + + /** + * + * @author hansonr + * + */ + public static class ListIterator implements Iterator { + + ListIterator() {/* restricted */} + + public JSONList list; + int pt = -1; + + @Override + public boolean hasNext() { + @SuppressWarnings("unused") + boolean more; + /** + * @j2sNative + * + * more = this.list && (this.pt < this.list.size); + * if (!more) { + * this.list = null; + * this.pt = -1; + * } + * return more; + */ + { + return pt < list.size(); + } + } + + @Override + public Object next() { + Object o = null; + /** + * @j2sNative o = this.list.elementData[this.pt++]; + * + */ + + return toObject(o); + } + } + } + + /** + * A simple encoding of sequential key/value pairs for a jQuery.ajax call. If + * the first key is "url" and the second is an object, then the ajax object is + * attached to that url as well, just for transport purposes within the system. + * + * @param keyValues assumed to be simple String,Object pairs. String objects + * will be surrounded by double quotes. + */ + public static Object setAjax(Object... keyValues) { + Object ajax = null; + /** + * @j2sNative ajax = {}; if (keyValues[0] == "url" && typeof keyValues[1] == + * "object") { ajax = keyValues[1].ajax || (keyValues[1].ajax = ajax); } + * + * for (var i = 0; i < keyValues.length;) { var key = keyValues[i++]; + * var val = keyValues[i++]; ajax[key] = val; } + */ + return ajax; + } + + public static void setAjax(URL url) { + setAjax("url", url, "dataType", "json", "async", Boolean.FALSE); + } + + public static BufferedReader getJSONReader(InputStream is) { + return new JSONReader(is); + } + + public static class JSONReader extends BufferedReader { + Object data; + + public JSONReader(InputStream in) { + super((Reader) (Object) in); + // could be buffered + data = toObject(/** @j2sNative $in._ajaxData || $in.$in && $in.$in._ajaxData || */ null); + + } + + public JSONReader(Reader in) { + super(in); + // could be buffered + data = toObject(/** @j2sNative $in._ajaxData || $in.$in && $in.$in._ajaxData || */ null); + } + + public JSONReader(String json) { + super((Reader) (Object) ""); + data = toObject(/** @j2sNative swingjs.JSUtil.parseJSON$S(json)|| */null); + } + + @Override + public void close() { + data = null; + try { + super.close(); + } catch (IOException e) { + // ignore, especially if we set $in to a string! + } + } + } + + @SuppressWarnings("resource") + public static Object parse(String json) { + return new JSONReader(json).data; + } + + public static Object parse(Reader br) { + return ((JSONReader) br).data; + } + + /** + * Get an object in the JSON associative array. + * @param br + * @param key + * @return + */ + @SuppressWarnings("unused") + public static Object toObject(Object o) { + if (o == null) + return null; + String type = /** @j2sNative (typeof o) + */""; + switch (type) { + case "string": + return o; + case "number": + double n = 0; + if (/** @j2sNative (n = o) == (n|0) || */false) + return Long.valueOf((long) n); + return Double.valueOf(n); + case "boolean": + return Boolean.valueOf(/** @j2sNative !!o || */false); + case "object": + boolean isArray = /** @j2sNative o instanceof Array || */false; + if (isArray) { + return toList((Object[]) o); + } + return toMap(o); + default: + return o; + } + } + + Object get(String key) { + /** + * @j2sNative + * + * return C$.toObject$O(this[key]); + */ + { + return null; + } + } + boolean contains(String key) { + /** + * @j2sNative + * + * return typeof this[key] != "undefined" + */ + { + return false; + } + } + + @SuppressWarnings("unchecked") + private static Hashtable toMap(Object map) { + /** + * @j2sNative + * map.get$O = C$.prototype.get$S; + * map.contains$O = C$.prototype.contains$S; + */ + return (Hashtable) map; + } + + private static List toList(Object[] a) { + return new JSONList(a); + } + +} -- 1.7.10.2