/* * Copyright © 2016 Keith Packard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ package org.altusmetrum.altoslib_14; import java.io.*; import java.util.*; import java.text.*; import java.lang.*; import java.lang.reflect.*; class JsonUtil { Writer quote(Writer writer, String a) throws IOException { writer.append("\""); for (int i = 0; i < a.length(); i++) { char c = a.charAt(i); switch (c) { case '"': case '\\': writer.append('\\').append(c); break; case '\n': writer.append("\\n"); break; default: writer.append(c); break; } } writer.append("\""); return writer; } Writer append(Writer result, AltosJson value, int indent, boolean pretty) throws IOException { value.append(result, indent, pretty); return result; } Writer append(Writer result, String string) throws IOException { result.append(string); return result; } Writer indent(Writer result, int indent) throws IOException { result.append("\n"); for (int i = 0; i < indent; i++) result.append("\t"); return result; } NumberFormat _nf_json; NumberFormat nf_json() { if (_nf_json == null) { DecimalFormat nf = (DecimalFormat) NumberFormat.getNumberInstance(Locale.ROOT); nf.setParseIntegerOnly(false); nf.setGroupingUsed(false); nf.setMaximumFractionDigits(17); nf.setMinimumFractionDigits(0); nf.setMinimumIntegerDigits(1); nf.setDecimalSeparatorAlwaysShown(false); _nf_json = nf; } return _nf_json; } } class JsonHash extends JsonUtil { Hashtable hash; void append_hash(Writer result, int indent, boolean pretty) throws IOException { boolean first = true; result.append("{"); ArrayList key_list = new ArrayList(hash.keySet()); Collections.sort(key_list, new Comparator() { @Override public int compare(String a, String b) { return a.compareTo(b); } }); for (String key : key_list) { AltosJson value = hash.get(key); if (!first) result.append(","); first = false; if (pretty) indent(result, indent+1); quote(result, key); append(result, ": "); append(result, value, indent+1, pretty); } if (pretty) indent(result, indent); append(result, "}"); } void put(String key, AltosJson value) { hash.put(key, value); } AltosJson get(String key) { return hash.get(key); } JsonHash() { hash = new Hashtable(); } } class JsonArray extends JsonUtil { ArrayList array; void append_array(Writer result, int indent, boolean pretty) throws IOException { boolean first = true; append(result, "["); for (int i = 0; i < array.size(); i++) { AltosJson value = array.get(i); if (!first) append(result, ","); first = false; if (pretty) indent(result, indent+1); append(result, value, indent+1, pretty); } if (pretty) indent(result, indent); append(result, "]"); } void put(int index, AltosJson value) { if (index >= array.size()) array.add(index, value); else array.set(index, value); } AltosJson get(int index) { if (index < 0 || index > array.size()) return null; return array.get(index); } int size() { return array.size(); } JsonArray() { array = new ArrayList(); } } class JsonToken { double dval; long lval; String sval; boolean bval; int token; static final int _string = 0; static final int _double = 1; static final int _long = 2; static final int _boolean = 3; static final int _oc = 4; static final int _cc = 5; static final int _os = 6; static final int _cs = 7; static final int _comma = 8; static final int _colon = 9; static final int _end = 10; static final int _error = 11; static final int _none = 12; static String token_name(int token) { switch (token) { case _string: return "string"; case _double: return "number"; case _long: return "number"; case _boolean: return "boolean"; case _oc: return "{"; case _cc: return "}"; case _os: return "["; case _cs: return "]"; case _comma: return ","; case _colon: return ":"; case _end: return ""; case _error: return ""; default: return ""; } } String token_name() { return token_name(token); } JsonToken(int token) { this.token = token; } JsonToken(int token, boolean bval) { this.token = token; this.bval = bval; } JsonToken(int token, double dval) { this.token = token; this.dval = dval; } JsonToken(int token, long lval) { this.token = token; this.lval = lval; } JsonToken(int token, String sval) { this.token = token; this.sval = sval; } JsonToken(int token, Writer bval) { this(token, bval.toString()); } } /* * Lexer for json */ class JsonLexer extends JsonUtil { InputStream f; int line; int ungot = -2; StringBuffer pending_token; private JsonToken token; static class keyword { String word; JsonToken token; JsonToken match(String value) { if (word.equals(value)) return token; return null; } keyword(String word, JsonToken token) { this.word = word; this.token = token; } } /* boolean values are the only keywords in json */ static keyword[] keywords = { new keyword("true", new JsonToken(JsonToken._boolean, true)), new keyword("false", new JsonToken(JsonToken._boolean, false)), new keyword("NegInfinity", new JsonToken(JsonToken._double, Double.NEGATIVE_INFINITY)), new keyword("Infinity", new JsonToken(JsonToken._double, Double.POSITIVE_INFINITY)), new keyword("NaN", new JsonToken(JsonToken._double, Double.NaN)) }; static JsonToken keyword(String word) { for (int i = 0; i < keywords.length; i++) { JsonToken token = keywords[i].match(word); if (token != null) return token; } return null; } /* Get the next char (-1 for EOF) */ int ch() throws IOException { int c; if (ungot != -2) { c = ungot; ungot = -2; } else c = f.read(); if (c != -1) pending_token.append((char) c); if (c == '\n') ++line; return c; } void unch(int c) { if (ungot != -2) throw new IllegalArgumentException("ungot buffer full"); pending_token.deleteCharAt( pending_token.length()-1); if (c == '\n') --line; ungot = c; } String last_token_string() { if (pending_token == null) return null; return pending_token.toString(); } static boolean is_long_range(double d) { return -9223372036854775808.0 <= d && d <= 9223372036854775807.0; } JsonToken lex() { pending_token = new StringBuffer(); try { for (;;) { int c = ch(); switch (c) { case -1: return new JsonToken(JsonToken._end); case '\n': case ' ': case '\t': continue; case '{': return new JsonToken(JsonToken._oc); case '}': return new JsonToken(JsonToken._cc); case '[': return new JsonToken(JsonToken._os); case ']': return new JsonToken(JsonToken._cs); case ',': return new JsonToken(JsonToken._comma); case ':': return new JsonToken(JsonToken._colon); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': case '-': case '+': StringBuffer dbuf = new StringBuffer(); boolean is_double = false; while (Character.isDigit(c) || c == '.' || c == '+' || c == '-' || c == 'e' || c == 'E') { if (c == '.' || c == 'E') is_double = true; dbuf.appendCodePoint(c); c = ch(); } unch(c); String dstr = dbuf.toString(); double dval; try { dval = nf_json().parse(dstr).doubleValue(); } catch (ParseException pe) { return new JsonToken(JsonToken._error, dstr); } if (is_double || !is_long_range(dval)) return new JsonToken(JsonToken._double, dval); else { long lval = Long.parseLong(dstr); return new JsonToken(JsonToken._long, lval); } case '"': Writer bval = new StringWriter(); for (;;) { c = ch(); if (c == '"') break; if (c == '\\') { c = ch(); switch (c) { case 'n': c = '\n'; break; case 't': c = '\t'; break; default: break; } } bval.write(c); } return new JsonToken(JsonToken._string, bval); default: if (Character.isLetter(c)) { StringBuffer tbuf = new StringBuffer(); do { tbuf.appendCodePoint(c); c = ch(); } while (Character.isLetter(c)); unch(c); JsonToken token = keyword(tbuf.toString()); if (token != null) return token; } break; } } } catch (IOException ie) { return new JsonToken(JsonToken._error, ""); } } void next() { token = null; } JsonToken token() { if (token == null) token = lex(); return token; } JsonToken expect(int e) { JsonToken t = token(); if (t.token != e) throw new IllegalArgumentException(String.format("got \"%s\" while expecting \"%s\"", token.token_name(), JsonToken.token_name(e))); next(); return t; } JsonLexer(String s) { f = new AltosStringInputStream(s); line = 1; token = null; } JsonLexer(InputStream f) { this.f = f; line = 1; token = null; } } /* * Parse a json string into a AltosJson object */ class JsonParse { JsonLexer lexer; void parse_error(String format, Object ... arguments) { throw new IllegalArgumentException(String.format("line %d: JSON parse error %s\n", lexer.line, String.format(format, arguments))); } /* Hashes are { string: value ... } */ JsonHash hash() { JsonHash hash = new JsonHash(); /* skip the open brace */ lexer.next(); for (;;) { /* Allow for empty hashes */ if (lexer.token().token == JsonToken._cc) { lexer.next(); return hash; } /* string : value */ String key = lexer.expect(JsonToken._string).sval; lexer.expect(JsonToken._colon); AltosJson value = value(); hash.put(key, value); switch (lexer.token().token) { case JsonToken._comma: lexer.next(); break; case JsonToken._cc: lexer.next(); return hash; default: parse_error("got %s expect \",\" or \"}\"", lexer.token().token_name()); return null; } } } /* Arrays are [ value ... ] */ JsonArray array() { JsonArray array = new JsonArray(); lexer.next(); for (int i = 0;; i++) { /* Allow for empty arrays */ if (lexer.token().token == JsonToken._cs) { lexer.next(); return array; } AltosJson value = value(); array.put(i, value); switch (lexer.token().token) { case JsonToken._comma: lexer.next(); break; case JsonToken._cs: lexer.next(); return array; default: parse_error("got %s expect \",\" or \"]\"", lexer.token().token_name()); return null; } } } /* Json is a simple LL language; one token is sufficient to * identify the next object in the input */ AltosJson value() { switch (lexer.token().token) { case JsonToken._oc: return new AltosJson(hash()); case JsonToken._os: return new AltosJson(array()); case JsonToken._double: double dval = lexer.token().dval; lexer.next(); return new AltosJson(dval); case JsonToken._long: long lval = lexer.token().lval; lexer.next(); return new AltosJson(lval); case JsonToken._string: String sval = lexer.token().sval; lexer.next(); return new AltosJson(sval); case JsonToken._boolean: boolean bval = lexer.token().bval; lexer.next(); return new AltosJson(bval); default: parse_error("Unexpected token \"%s\"", lexer.token().token_name()); } return null; } AltosJson parse() { lexer.next(); return value(); } JsonParse(String s) { lexer = new JsonLexer(s); } JsonParse(InputStream f) { lexer = new JsonLexer(f); } } public class AltosJson extends JsonUtil { private static final int type_none = 0; private static final int type_hash = 1; private static final int type_array = 2; private static final int type_double = 3; private static final int type_long = 4; private static final int type_string = 5; private static final int type_boolean = 6; private int type; private JsonHash hash; private JsonArray array; private double d_number; private long l_number; private String string; private boolean bool; /* Generate string representation of the value */ Writer append(Writer result, int indent, boolean pretty) throws IOException { switch (type) { case type_hash: hash.append_hash(result, indent, pretty); break; case type_array: array.append_array(result, indent, pretty); break; case type_double: if (Double.isInfinite(d_number)) { if (d_number < 0) result.append("NegInfinity"); else result.append("Infinity"); } else if (Double.isNaN(d_number)) { result.append("NaN"); } else { String dval = nf_json().format(d_number); if (dval.equals("-0")) dval = "0"; result.append(dval); } break; case type_long: result.append(Long.valueOf(l_number).toString()); break; case type_string: quote(result, string); break; case type_boolean: result.append(bool ? "true" : "false"); break; } return result; } private String toString(int indent, boolean pretty) { try { Writer result = new StringWriter(); append(result, indent, pretty); return result.toString(); } catch (Exception e) { return null; } } public String toString() { return toString(0, false); } public String toPrettyString() { return toString(0, true); } public void write(Writer w, int indent, boolean pretty) throws IOException { append(w, indent, pretty); } public void write(Writer w) throws IOException { write(w, 0, true); } /* Parse string representation to a value */ public static AltosJson fromString(String string) { JsonParse parse = new JsonParse(string); try { return parse.parse(); } catch (IllegalArgumentException ie) { System.out.printf("json:\n%s\n%s\n", string, ie.getMessage()); return null; } } public static AltosJson fromInputStream(InputStream f) { JsonParse parse = new JsonParse(f); try { return parse.parse(); } catch (IllegalArgumentException ie) { System.out.printf("json:\n%s\n", ie.getMessage()); return null; } } /* Accessor functions */ private boolean assert_type(boolean setting, int type, int other_type, String error) { if (setting && this.type == type_none) { this.type = type; return false; } if (this.type != type && this.type != other_type) throw new IllegalArgumentException(error); return true; } private boolean assert_type(boolean setting, int type, String error) { return assert_type(setting, type, type, error); } private void assert_hash(boolean setting) { if (!assert_type(setting, type_hash, "not a hash")) hash = new JsonHash(); } private void assert_array(boolean setting) { if (!assert_type(setting, type_array, "not an array")) array = new JsonArray(); } private void assert_number() { assert_type(false, type_double, type_long, "not a number"); } private void assert_double() { assert_type(true, type_double, type_long, "not a number"); } private void assert_long() { assert_type(true, type_long, type_double, "not a number"); } private void assert_string(boolean setting) { assert_type(setting, type_string, "not a string"); } private void assert_boolean(boolean setting) { assert_type(setting, type_boolean, "not a boolean"); } /* Primitive accessors */ public double number() { assert_number(); if (type == type_double) return d_number; else return (double) l_number; } public long l_number() { assert_number(); if (type == type_double) return (long) d_number; else return l_number; } public String string() { assert_string(false); return string; } public boolean bool() { assert_boolean(false); return bool; } public AltosJson get(int index) { assert_array(false); return array.get(index); } public AltosJson get(String key) { assert_hash(false); return hash.get(key); } public int size() { assert_array(false); return array.size(); } /* Typed accessors with defaulting */ public double get_double(String key, double def) { AltosJson value = get(key); if (value != null) { return value.number(); } return def; } public long get_long(String key, long def) { AltosJson value = get(key); if (value != null) return value.l_number(); return def; } public int get_int(String key, int def) { AltosJson value = get(key); if (value != null) return (int) value.l_number(); return def; } public String get_string(String key, String def) { AltosJson value = get(key); if (value != null) return value.string(); return def; } public boolean get_boolean(String key, boolean def) { AltosJson value = get(key); if (value != null) return value.bool(); return def; } public double get_double(int index, double def) { AltosJson value = get(index); if (value != null) return value.number(); return def; } public long get_long(int index, long def) { AltosJson value = get(index); if (value != null) return value.l_number(); return def; } public int get_int(int index, int def) { AltosJson value = get(index); if (value != null) return (int) value.l_number(); return def; } public String get_string(int index, String def) { AltosJson value = get(index); if (value != null) return value.string(); return def; } public boolean get_boolean(int index, boolean def) { AltosJson value = get(index); if (value != null) return value.bool(); return def; } public double[] get_double_array(String key, double[] def) { AltosJson value = get(key); if (value != null) { double[] ret = new double[value.size()]; for (int i = 0; i < value.size(); i++) ret[i] = value.get_double(i, def == null ? 0 : def[i]); return ret; } return def; } public int[] get_int_array(String key, int[] def) { AltosJson value = get(key); if (value != null) { int[] ret = new int[value.size()]; for (int i = 0; i < value.size(); i++) ret[i] = value.get_int(i, def == null ? 0 : def[i]); return ret; } return def; } /* Array setter functions */ public AltosJson put(int index, AltosJson value) { assert_array(true); array.put(index, value); return value; } public Object put(int index, Object value) { assert_array(true); if (value != null) array.put(index, new AltosJson(value)); return value; } public double put(int index, double value) { assert_array(true); array.put(index, new AltosJson(value)); return value; } public AltosJson put(int index, double[] value) { if (value != null) { assert_array(true); array.put(index, new AltosJson(value)); } return this; } public int[] put(int index, int[] value) { if (value != null) { assert_array(true); array.put(index, new AltosJson(value)); } return value; } public String put(int index, String value) { if (value != null) { assert_array(true); array.put(index, new AltosJson(value)); } return value; } public boolean put(int index, boolean value) { assert_array(true); array.put(index, new AltosJson(value)); return value; } /* Hash setter functions */ public AltosJson put(String key, AltosJson value) { assert_hash(true); hash.put(key, value); return value; } public Object put(String key, Object value) { assert_hash(true); if (value != null) hash.put(key, new AltosJson(value)); return value; } public double put(String key, double value) { assert_hash(true); hash.put(key, new AltosJson(value)); return value; } public String put(String key, String value) { if (value != null) { assert_hash(true); hash.put(key, new AltosJson(value)); } return value; } public boolean put(String key, boolean value) { assert_hash(true); hash.put(key, new AltosJson(value)); return value; } public AltosJson[] put(String key, AltosJson[] value) { if (value != null) { assert_hash(true); hash.put(key, new AltosJson(value)); } return value; } public double[] put(String key, double[] value) { if (value != null) { assert_hash(true); hash.put(key, new AltosJson(value)); } return value; } public int[] put(String key, int[] value) { if (value != null) { assert_hash(true); hash.put(key, new AltosJson(value)); } return value; } /* Primitive setter functions */ public double put(double value) { assert_double(); d_number = value; return value; } public byte put(byte value) { assert_long(); l_number = value; return value; } public char put(char value) { assert_long(); l_number = value; return value; } public int put(int value) { assert_long(); l_number = value; return value; } public long put(long value) { assert_long(); l_number = value; return value; } public String put(String value) { assert_string(true); string = value; return value; } public boolean put(boolean value) { assert_boolean(true); bool = value; return value; } private boolean isInnerClass(Class c) { for (Field field : c.getDeclaredFields()) if (field.isSynthetic()) return true; return false; } /* Construct an object of the specified class from the JSON * representation. * * This works as long as the structure is non-recursive, and * all inner classes are only members of their immediate outer * class */ @SuppressWarnings("unchecked") private Object make(Class c, Class enclosing_class, Object enclosing_object) { Object ret; if (c == Boolean.TYPE) { ret = bool(); } else if (c == Byte.TYPE) { ret = (Byte) (byte) l_number(); } else if (c == Character.TYPE) { ret = (Character) (char) l_number(); } else if (c == Integer.TYPE) { ret = (Integer) (int) l_number(); } else if (c == Long.TYPE) { ret = l_number(); } else if (c == Double.TYPE) { ret = number(); } else if (c == String.class) { ret = string(); } else if (c.isArray()) { assert_array(false); Class element_class = c.getComponentType(); if (element_class == Boolean.TYPE) { boolean[] array = (boolean[]) Array.newInstance(element_class, size()); for (int i = 0; i < array.length; i++) array[i] = (Boolean) get(i).make(element_class); ret = array; } else if (element_class == Byte.TYPE) { byte[] array = (byte[]) Array.newInstance(element_class, size()); for (int i = 0; i < array.length; i++) array[i] = (Byte) get(i).make(element_class); ret = array; } else if (element_class == Character.TYPE) { char[] array = (char[]) Array.newInstance(element_class, size()); for (int i = 0; i < array.length; i++) array[i] = (Character) get(i).make(element_class); ret = array; } else if (element_class == Integer.TYPE) { int[] array = (int[]) Array.newInstance(element_class, size()); for (int i = 0; i < array.length; i++) array[i] = (Integer) get(i).make(element_class); ret = array; } else if (element_class == Long.TYPE) { long[] array = (long[]) Array.newInstance(element_class, size()); for (int i = 0; i < array.length; i++) array[i] = (Long) get(i).make(element_class); ret = array; } else if (element_class == Double.TYPE) { double[] array = (double[]) Array.newInstance(element_class, size()); for (int i = 0; i < array.length; i++) array[i] = (Double) get(i).make(element_class); ret = array; } else { Object[] array = (Object[]) Array.newInstance(element_class, size()); for (int i = 0; i < array.length; i++) array[i] = get(i).make(element_class); ret = array; } } else { assert_hash(false); Object object = null; try { /* Inner classes have a hidden extra parameter * to the constructor. Assume that the enclosing object is * of the enclosing class and construct the object * based on that. */ if (enclosing_class != null && isInnerClass(c)) { Constructor ctor = ((Class)c).getDeclaredConstructor((Class) enclosing_class); object = ctor.newInstance(enclosing_object); } else { object = c.getDeclaredConstructor().newInstance(); } for (; c != Object.class; c = c.getSuperclass()) { for (Field field : c.getDeclaredFields()) { String fieldName = field.getName(); Class fieldClass = field.getType(); if (Modifier.isStatic(field.getModifiers())) continue; if (field.isSynthetic()) continue; try { AltosJson json = get(fieldName); if (json != null) { Object val = json.make(fieldClass, c, object); field.setAccessible(true); field.set(object, val); } } catch (IllegalAccessException ie) { System.out.printf("%s:%s %s\n", c.getName(), fieldName, ie.toString()); } } } ret = object; } catch (InvocationTargetException ie) { System.out.printf("%s: %s\n", c.getName(), ie.toString()); ret = null; } catch (NoSuchMethodException ie) { System.out.printf("%s: %s\n", c.getName(), ie.toString()); ret = null; } catch (InstantiationException ie) { System.out.printf("%s: %s\n", c.getName(), ie.toString()); ret = null; } catch (IllegalAccessException ie) { System.out.printf("%s: %s\n", c.getName(), ie.toString()); ret = null; } } return ret; } /* This is the public API for the * above function which doesn't handle * inner classes */ public Object make(Class c) { return make(c, null, null); } /* Constructors, one for each primitive type, String and Object */ public AltosJson(boolean bool) { type = type_boolean; this.bool = bool; } public AltosJson(byte number) { type = type_long; this.l_number = number; } public AltosJson(char number) { type = type_long; this.l_number = number; } public AltosJson(int number) { type = type_long; this.l_number = number; } public AltosJson(long number) { type = type_long; this.l_number = number; } public AltosJson(double number) { type = type_double; this.d_number = number; } public AltosJson(String string) { type = type_string; this.string = string; } public AltosJson(Object object) { if (object instanceof Boolean) { type = type_boolean; bool = (Boolean) object; } else if (object instanceof Byte) { type = type_long; l_number = (Byte) object; } else if (object instanceof Character) { type = type_long; l_number = (Character) object; } else if (object instanceof Integer) { type = type_long; l_number = (Integer) object; } else if (object instanceof Long) { type = type_long; l_number = (Long) object; } else if (object instanceof Double) { type = type_double; d_number = (Double) object; } else if (object instanceof String) { type = type_string; string = (String) object; } else if (object == null) { System.out.printf("unexpected null object\n"); } else if (object.getClass() == null) { System.out.printf("unexpected null object class\n"); } else if (object.getClass().isArray()) { assert_array(true); Class component_class = object.getClass().getComponentType(); if (component_class == Boolean.TYPE) { boolean[] array = (boolean[]) object; for (int i = 0; i < array.length; i++) put(i, new AltosJson(array[i])); } else if (component_class == Byte.TYPE) { byte[] array = (byte[]) object; for (int i = 0; i < array.length; i++) put(i, new AltosJson(array[i])); } else if (component_class == Character.TYPE) { char[] array = (char[]) object; for (int i = 0; i < array.length; i++) put(i, new AltosJson(array[i])); } else if (component_class == Integer.TYPE) { int[] array = (int[]) object; for (int i = 0; i < array.length; i++) put(i, new AltosJson(array[i])); } else if (component_class == Long.TYPE) { long[] array = (long[]) object; for (int i = 0; i < array.length; i++) put(i, new AltosJson(array[i])); } else if (component_class == Double.TYPE) { double[] array = (double[]) object; for (int i = 0; i < array.length; i++) put(i, new AltosJson(array[i])); } else { Object[] array = (Object[]) object; for (int i = 0; i < array.length; i++) put(i, new AltosJson(array[i])); } } else { assert_hash(true); for (Class c = object.getClass(); c != Object.class; c = c.getSuperclass()) { for (Field field : c.getDeclaredFields()) { String fieldName = field.getName(); /* XXX hack to allow fields to be not converted */ if (fieldName.startsWith("__")) continue; /* Skip static fields */ if (Modifier.isStatic(field.getModifiers())) continue; /* Skip synthetic fields. We're assuming * those are always an inner class reference * to the outer class object */ if (field.isSynthetic()) continue; try { /* We may need to force the field to be accessible if * it is private */ field.setAccessible(true); Object val = field.get(object); if (val != null) { AltosJson json = new AltosJson(val); put(fieldName, json); } } catch (IllegalAccessException ie) { System.out.printf("%s:%s %s\n", c.getName(), fieldName, ie.toString()); } } } } } /* Array constructors, one for each primitive type, String and Object */ public AltosJson(boolean[] bools) { assert_array(true); for(int i = 0; i < bools.length; i++) put(i, new AltosJson(bools[i])); } public AltosJson(byte[] numbers) { assert_array(true); for(int i = 0; i < numbers.length; i++) put(i, new AltosJson(numbers[i])); } public AltosJson(char[] numbers) { assert_array(true); for(int i = 0; i < numbers.length; i++) put(i, new AltosJson(numbers[i])); } public AltosJson(int[] numbers) { assert_array(true); for(int i = 0; i < numbers.length; i++) put(i, new AltosJson(numbers[i])); } public AltosJson(long[] numbers) { assert_array(true); for(int i = 0; i < numbers.length; i++) put(i, new AltosJson(numbers[i])); } public AltosJson(double[] numbers) { assert_array(true); for(int i = 0; i < numbers.length; i++) put(i, new AltosJson(numbers[i])); } public AltosJson(String[] strings) { assert_array(true); for(int i = 0; i < strings.length; i++) put(i, new AltosJson(strings[i])); } public AltosJson(AltosJson[] jsons) { assert_array(true); for (int i = 0; i < jsons.length; i++) put(i, jsons[i]); } public AltosJson(Object[] array) { assert_array(true); for (int i = 0; i < array.length; i++) put(i, new AltosJson(array[i])); } /* Empty constructor */ public AltosJson() { type = type_none; } public AltosJson(JsonHash hash) { type = type_hash; this.hash = hash; } public AltosJson(JsonArray array) { type = type_array; this.array = array; } }