From 93de1d7ec841c55f5a1a63d34b422780a6fbe3c3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 17 Jun 2016 00:00:09 -0700 Subject: altoslib: Add JSON-based object saving/restoring code This uses Java reflection to construct JSON strings for most Java objects. Signed-off-by: Keith Packard --- altoslib/AltosJson.java | 1268 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1268 insertions(+) create mode 100644 altoslib/AltosJson.java (limited to 'altoslib/AltosJson.java') diff --git a/altoslib/AltosJson.java b/altoslib/AltosJson.java new file mode 100644 index 00000000..6ae7e7dc --- /dev/null +++ b/altoslib/AltosJson.java @@ -0,0 +1,1268 @@ +/* + * 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; version 2 of the License. + * + * 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_11; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.lang.*; +import java.lang.reflect.*; + +class JsonUtil { + StringBuffer quote(StringBuffer result, String a) { + result.append("\""); + for (int i = 0; i < a.length(); i++) { + char c = a.charAt(i); + + switch (c) { + case '"': + case '\\': + result.append('\\').append(c); + break; + case '\n': + result.append("\\n"); + break; + default: + result.append(c); + break; + } + } + result.append("\""); + return result; + } + + StringBuffer append(StringBuffer result, AltosJson value, int indent, boolean pretty) { + value.append(result, indent, pretty); + return result; + } + + StringBuffer append(StringBuffer result, String string) { + result.append(string); + return result; + } + + StringBuffer indent(StringBuffer result, int indent) { + result.append("\n"); + for (int i = 0; i < indent; i++) + result.append("\t"); + return result; + } + static NumberFormat get_nf_json() { + 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); + return nf; + } + + static NumberFormat nf_json = get_nf_json(); +} + +class JsonHash extends JsonUtil { + Hashtable hash; + + void append_hash(StringBuffer result, int indent, boolean pretty) { + 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(StringBuffer result, int indent, boolean pretty) { + 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 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, StringBuffer bval) { + this(token, bval.toString()); + } +} + +/* + * Lexer for json + */ +class JsonLexer extends JsonUtil { + StringReader f; + int line; + int ungot = -2; + StringBuffer pending_token; + 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)), + }; + + 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 '"': + StringBuffer bval = new StringBuffer(); + 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.appendCodePoint(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 = lex(); + } + + 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 StringReader(s); + 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); + } +} + +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 + */ + StringBuffer append(StringBuffer result, int indent, boolean pretty) { + 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: + String dval = nf_json.format(d_number); + if (dval.equals("-0")) + dval = "0"; + result.append(dval); + break; + case type_long: + result.append(new Long(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) { + StringBuffer result = new StringBuffer(); + append(result, indent, pretty); + return result.toString(); + } + + public String toString() { + return toString(0, false); + } + + public String toPrettyString() { + return toString(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; + } + } + + /* 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 + */ + 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 == 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.newInstance(); + } + for (; c != null; c = c.getSuperclass()) { + for (Field field : c.getDeclaredFields()) { + String fieldName = field.getName(); + Class fieldClass = field.getType(); + String className = fieldClass.getName(); + + 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) { + } + } + } + ret = object; + } catch (InvocationTargetException ie) { + ret = null; + } catch (NoSuchMethodException ie) { + ret = null; + } catch (InstantiationException ie) { + ret = null; + } catch (IllegalAccessException ie) { + 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.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 != null; c = c.getSuperclass()) { + for (Field field : c.getDeclaredFields()) { + String fieldName = field.getName(); + Class fieldClass = field.getType(); + String className = fieldClass.getName(); + + /* 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) { + } + } + } + } + } + + /* 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; + } +} -- cgit v1.2.3 From 1dce20f7eee56166ac61798ca26eeb323dc8f012 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 17 Jun 2016 00:52:38 -0700 Subject: altoslib: Get rid of manual JSON encoding stuff Now that the reflective JSON stuff is working, we can delete all of the manual code. Signed-off-by: Keith Packard --- altoslib/AltosCompanion.java | 28 +--- altoslib/AltosFrequency.java | 22 +-- altoslib/AltosGPS.java | 63 +------- altoslib/AltosGPSSat.java | 25 +-- altoslib/AltosGreatCircle.java | 34 +---- altoslib/AltosIMU.java | 33 +--- altoslib/AltosJson.java | 23 ++- altoslib/AltosMag.java | 26 +--- altoslib/AltosMs5607.java | 44 +----- altoslib/AltosPreferences.java | 8 +- altoslib/AltosQuaternion.java | 22 +-- altoslib/AltosRotation.java | 17 +-- altoslib/AltosState.java | 340 +---------------------------------------- altoslib/Makefile.am | 1 - 14 files changed, 39 insertions(+), 647 deletions(-) (limited to 'altoslib/AltosJson.java') diff --git a/altoslib/AltosCompanion.java b/altoslib/AltosCompanion.java index 2db8ea1b..d517fd4f 100644 --- a/altoslib/AltosCompanion.java +++ b/altoslib/AltosCompanion.java @@ -19,7 +19,7 @@ package org.altusmetrum.altoslib_11; import java.io.*; -public class AltosCompanion implements AltosJsonable { +public class AltosCompanion { public final static int board_id_telescience = 0x0a; public final static int MAX_CHANNELS = 12; @@ -37,30 +37,4 @@ public class AltosCompanion implements AltosJsonable { channels = MAX_CHANNELS; companion_data = new int[channels]; } - - public AltosJson json() { - AltosJson j = new AltosJson(); - - j.put("tick", tick); - j.put("board_id", board_id); - j.put("update_period", update_period); - j.put("channels", channels); - j.put("companion_data", companion_data); - return j; - } - - public AltosCompanion(AltosJson j) { - tick = j.get_int("tick", tick); - board_id = j.get_int("board_id", board_id); - update_period = j.get_int("update_period", update_period); - channels = j.get_int("channels", channels); - companion_data = j.get_int_array("companion_data", new int[channels]); - } - - public static AltosCompanion fromJson(AltosJson j, AltosCompanion def) { - if (j == null) - return def; - - return new AltosCompanion(j); - } } diff --git a/altoslib/AltosFrequency.java b/altoslib/AltosFrequency.java index 3c1631a8..874a9bcc 100644 --- a/altoslib/AltosFrequency.java +++ b/altoslib/AltosFrequency.java @@ -21,7 +21,7 @@ import java.io.*; import java.util.*; import java.text.*; -public class AltosFrequency implements AltosJsonable { +public class AltosFrequency { public double frequency; public String description; @@ -57,28 +57,8 @@ public class AltosFrequency implements AltosJsonable { return diff < 0.010; } - - public AltosJson json() { - AltosJson j = new AltosJson(); - - j.put("frequency", frequency); - j.put("description", description); - return j; - } - public AltosFrequency(double f, String d) { frequency = f; description = d; } - - private AltosFrequency(AltosJson j) { - frequency = j.get_double("frequency", 0.0); - description = j.get_string("description", ""); - } - - public static AltosFrequency fromJson(AltosJson j, AltosFrequency def) { - if (j == null) - return def; - return new AltosFrequency(j); - } } diff --git a/altoslib/AltosGPS.java b/altoslib/AltosGPS.java index ba2eda1b..d29ccdd1 100644 --- a/altoslib/AltosGPS.java +++ b/altoslib/AltosGPS.java @@ -21,7 +21,7 @@ import java.text.*; import java.util.concurrent.*; import java.io.*; -public class AltosGPS implements Cloneable, AltosJsonable { +public class AltosGPS implements Cloneable { public final static int MISSING = AltosLib.MISSING; @@ -388,65 +388,4 @@ public class AltosGPS implements Cloneable, AltosJsonable { break; } } - - public AltosJson json() { - AltosJson j = new AltosJson(); - - j.put("nsat", nsat); - j.put("locked", locked); - j.put("connected", connected); - j.put("lat", lat); - j.put("lon", lon); - j.put("alt", alt); - j.put("year", year); - j.put("month", month); - j.put("day", day); - j.put("hour", hour); - j.put("minute", minute); - j.put("second", second); - - j.put("ground_speed", ground_speed); - j.put("course", course); - j.put("climb_rate", climb_rate); - j.put("pdop", pdop); - j.put("hdop", hdop); - j.put("vdop", vdop); - j.put("h_error", h_error); - j.put("v_error", v_error); - j.put("cc_gps_sat", cc_gps_sat); - return j; - } - - public AltosGPS(AltosJson j) { - init(); - nsat = j.get_int("nsat", nsat); - locked = j.get_boolean("locked", locked); - connected = j.get_boolean("connected", connected); - lat = j.get_double("lat", lat); - lon = j.get_double("lon", lon); - alt = j.get_double("alt", alt); - year = j.get_int("year", year); - month = j.get_int("month", month); - day = j.get_int("day", day); - hour = j.get_int("hour", hour); - minute = j.get_int("minute", minute); - second = j.get_int("second", second); - - ground_speed = j.get_double("ground_speed", ground_speed); - course = j.get_int("course", course); - climb_rate = j.get_double("climb_rate", climb_rate); - pdop = j.get_double("pdop", pdop); - hdop = j.get_double("hdop", hdop); - vdop = j.get_double("vdop", vdop); - h_error = j.get_double("h_error", h_error); - v_error = j.get_double("v_error", v_error); - cc_gps_sat = AltosGPSSat.json_array(j.get("cc_gps_sat")); - } - - public static AltosGPS fromJson(AltosJson j, AltosGPS def) { - if (j == null) - return def; - - return new AltosGPS(j); - } } diff --git a/altoslib/AltosGPSSat.java b/altoslib/AltosGPSSat.java index 8cdeed0e..8b95c150 100644 --- a/altoslib/AltosGPSSat.java +++ b/altoslib/AltosGPSSat.java @@ -22,7 +22,7 @@ import java.text.*; import java.util.*; import java.util.concurrent.*; -public class AltosGPSSat implements AltosJsonable { +public class AltosGPSSat { public int svid; public int c_n0; @@ -33,28 +33,5 @@ public class AltosGPSSat implements AltosJsonable { public AltosGPSSat() { } - - public AltosJson json() { - AltosJson j = new AltosJson(); - j.put("svid", svid); - j.put("c_n0", c_n0); - return j; - } - - private AltosGPSSat(AltosJson j) { - svid = j.get_int("svid", 0); - c_n0 = j.get_int("c_n0", 0); - } - - static public AltosGPSSat[] json_array(AltosJson j) { - if (j == null) - return null; - - int size = j.size(); - AltosGPSSat[] sats = new AltosGPSSat[size]; - for (int i = 0; i < size; i++) - sats[i] = new AltosGPSSat(j.get(i)); - return sats; - } } diff --git a/altoslib/AltosGreatCircle.java b/altoslib/AltosGreatCircle.java index f2c1783d..a2f12807 100644 --- a/altoslib/AltosGreatCircle.java +++ b/altoslib/AltosGreatCircle.java @@ -20,7 +20,7 @@ package org.altusmetrum.altoslib_11; import java.lang.Math; import java.io.*; -public class AltosGreatCircle implements Cloneable, AltosJsonable { +public class AltosGreatCircle implements Cloneable { public double distance; public double bearing; public double range; @@ -71,7 +71,10 @@ public class AltosGreatCircle implements Cloneable, AltosJsonable { course = 2 * Math.PI-course; } distance = d * earth_radius; - bearing = course * 180/Math.PI; + if (Double.isNaN(course) || Double.isInfinite(course)) + bearing = 0; + else + bearing = course * 180/Math.PI; double height_diff = end_alt - start_alt; range = Math.sqrt(distance * distance + height_diff * height_diff); @@ -103,31 +106,4 @@ public class AltosGreatCircle implements Cloneable, AltosJsonable { range = 0; elevation = 0; } - - public AltosJson json() { - AltosJson j = new AltosJson(); - - j.put("distance", distance); - j.put("bearing", bearing); - j.put("range", range); - j.put("elevation", elevation); - - return j; - } - - public AltosGreatCircle(AltosJson j) { - this(); - - distance = j.get_double("distance", distance); - bearing = j.get_double("bearing", bearing); - range = j.get_double("range", range); - elevation = j.get_double("elevation", elevation); - } - - public static AltosGreatCircle fromJson(AltosJson j, AltosGreatCircle def) { - if (j == null) - return def; - - return new AltosGreatCircle(j); - } } diff --git a/altoslib/AltosIMU.java b/altoslib/AltosIMU.java index 672c6111..dbadcf89 100644 --- a/altoslib/AltosIMU.java +++ b/altoslib/AltosIMU.java @@ -20,7 +20,7 @@ package org.altusmetrum.altoslib_11; import java.util.concurrent.*; import java.io.*; -public class AltosIMU implements Cloneable, AltosJsonable { +public class AltosIMU implements Cloneable { public int accel_along; public int accel_across; public int accel_through; @@ -115,35 +115,4 @@ public class AltosIMU implements Cloneable, AltosJsonable { break; } } - - public AltosIMU (AltosJson j) { - this(); - - accel_along = j.get_int("accel_along", accel_along); - accel_across = j.get_int("accel_across", accel_across); - accel_through = j.get_int("accel_through", accel_through); - - gyro_roll = j.get_int("gyro_roll", gyro_roll); - gyro_pitch = j.get_int("gyro_pitch", gyro_pitch); - gyro_yaw = j.get_int("gyro_yaw", gyro_yaw); - } - - static public AltosIMU fromJson(AltosJson j, AltosIMU def) { - if (j == null) - return def; - return new AltosIMU(j); - } - - public AltosJson json() { - AltosJson j = new AltosJson(); - - j.put("accel_along", accel_along); - j.put("accel_across", accel_across); - j.put("accel_through", accel_through); - - j.put("gyro_roll", gyro_roll); - j.put("gyro_pitch", gyro_pitch); - j.put("gyro_yaw", gyro_yaw); - return j; - } } diff --git a/altoslib/AltosJson.java b/altoslib/AltosJson.java index 6ae7e7dc..e979a459 100644 --- a/altoslib/AltosJson.java +++ b/altoslib/AltosJson.java @@ -280,6 +280,9 @@ class JsonLexer extends JsonUtil { 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) { @@ -583,10 +586,19 @@ public class AltosJson extends JsonUtil { array.append_array(result, indent, pretty); break; case type_double: - String dval = nf_json.format(d_number); - if (dval.equals("-0")) - dval = "0"; - result.append(dval); + 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(new Long(l_number).toString()); @@ -1030,7 +1042,6 @@ public class AltosJson extends JsonUtil { for (Field field : c.getDeclaredFields()) { String fieldName = field.getName(); Class fieldClass = field.getType(); - String className = fieldClass.getName(); if (Modifier.isStatic(field.getModifiers())) continue; @@ -1165,8 +1176,6 @@ public class AltosJson extends JsonUtil { for (Class c = object.getClass(); c != null; c = c.getSuperclass()) { for (Field field : c.getDeclaredFields()) { String fieldName = field.getName(); - Class fieldClass = field.getType(); - String className = fieldClass.getName(); /* Skip static fields */ if (Modifier.isStatic(field.getModifiers())) diff --git a/altoslib/AltosMag.java b/altoslib/AltosMag.java index 8d40bc60..5864529f 100644 --- a/altoslib/AltosMag.java +++ b/altoslib/AltosMag.java @@ -20,7 +20,7 @@ package org.altusmetrum.altoslib_11; import java.util.concurrent.*; import java.io.*; -public class AltosMag implements Cloneable, AltosJsonable { +public class AltosMag implements Cloneable { public int along; public int across; public int through; @@ -93,28 +93,4 @@ public class AltosMag implements Cloneable, AltosJsonable { break; } } - - public AltosJson json() { - AltosJson j = new AltosJson(); - - j.put("along", along); - j.put("across", across); - j.put("through", through); - return j; - } - - public AltosMag(AltosJson j) { - this(); - - along = j.get_int("along", along); - across = j.get_int("across", across); - through = j.get_int("through", through); - } - - public static AltosMag fromJson(AltosJson j, AltosMag def) { - if (j == null) - return def; - - return new AltosMag(j); - } } diff --git a/altoslib/AltosMs5607.java b/altoslib/AltosMs5607.java index a769223e..e40479b1 100644 --- a/altoslib/AltosMs5607.java +++ b/altoslib/AltosMs5607.java @@ -20,7 +20,7 @@ package org.altusmetrum.altoslib_11; import java.util.concurrent.*; import java.io.*; -public class AltosMs5607 implements AltosJsonable { +public class AltosMs5607 { public int reserved; public int sens; public int off; @@ -166,46 +166,4 @@ public class AltosMs5607 implements AltosJsonable { } convert(); } - - public AltosJson json() { - AltosJson j = new AltosJson(); - - j.put("reserved", reserved); - j.put("sens", sens); - j.put("off", off); - j.put("tcs", tcs); - j.put("tco", tco); - j.put("tref", tref); - j.put("tempsens", tempsens); - j.put("crc", crc); - j.put("raw_pres", raw_pres); - j.put("raw_temp", raw_temp); - j.put("pa", pa); - j.put("cc", cc); - return j; - } - - public AltosMs5607(AltosJson j) { - this(); - - reserved = j.get_int("reserved", reserved); - sens = j.get_int("sens", sens); - off = j.get_int("off", off); - tcs = j.get_int("tcs", tcs); - tco = j.get_int("tco", tco); - tref = j.get_int("tref", tref); - tempsens = j.get_int("tempsens", tempsens); - crc = j.get_int("crc", crc); - raw_pres = j.get_int("raw_pres", raw_pres); - raw_temp = j.get_int("raw_temp", raw_temp); - pa = j.get_int("pa", pa); - cc = j.get_int("cc", cc); - } - - public static AltosMs5607 fromJson(AltosJson j, AltosMs5607 def) { - if (j == null) - return def; - - return new AltosMs5607(j); - } } diff --git a/altoslib/AltosPreferences.java b/altoslib/AltosPreferences.java index 51fc4205..569aaa54 100644 --- a/altoslib/AltosPreferences.java +++ b/altoslib/AltosPreferences.java @@ -365,7 +365,7 @@ public class AltosPreferences { public static void set_state(AltosState state) { synchronized(backend) { - backend.putJson(String.format(statePreferenceFormat, state.serial), state.json()); + backend.putJson(String.format(statePreferenceFormat, state.serial), new AltosJson(state)); backend.putInt(statePreferenceLatest, state.serial); flush_preferences(); } @@ -405,10 +405,12 @@ public class AltosPreferences { public static AltosState state(int serial) { synchronized(backend) { try { - return AltosState.fromJson(backend.getJson(String.format(statePreferenceFormat, serial))); + AltosJson json = backend.getJson(String.format(statePreferenceFormat, serial)); + if (json != null) + return (AltosState) (json.make(AltosState.class)); } catch (Exception e) { - return null; } + return null; } } diff --git a/altoslib/AltosQuaternion.java b/altoslib/AltosQuaternion.java index 98c2fe51..79559429 100644 --- a/altoslib/AltosQuaternion.java +++ b/altoslib/AltosQuaternion.java @@ -17,7 +17,7 @@ package org.altusmetrum.altoslib_11; -public class AltosQuaternion implements AltosJsonable { +public class AltosQuaternion { double r; /* real bit */ double x, y, z; /* imaginary bits */ @@ -154,24 +154,4 @@ public class AltosQuaternion implements AltosJsonable { c_x * s_y * c_z + s_x * c_y * s_z, c_x * c_y * s_z - s_x * s_y * c_z); } - - public AltosJson json() { - AltosJson j = new AltosJson(); - - j.put("r", r); - j.put("x", x); - j.put("y", y); - j.put("z", z); - return j; - } - - public AltosQuaternion(AltosJson j) { - if (j == null) - return; - - r = j.get_double("r", 1); - x = j.get_double("x", 0); - y = j.get_double("y", 0); - z = j.get_double("z", 0); - } } diff --git a/altoslib/AltosRotation.java b/altoslib/AltosRotation.java index 6db0b541..97cf7896 100644 --- a/altoslib/AltosRotation.java +++ b/altoslib/AltosRotation.java @@ -17,7 +17,7 @@ package org.altusmetrum.altoslib_11; -public class AltosRotation implements AltosJsonable { +public class AltosRotation extends AltosQuaternion { private AltosQuaternion rotation; public double tilt() { @@ -48,22 +48,7 @@ public class AltosRotation implements AltosJsonable { rotation = up.vectors_to_rotation(orient); } - public AltosRotation(AltosJson j) { - rotation = new AltosQuaternion(j); - } - public AltosRotation() { rotation = new AltosQuaternion(); } - - public AltosJson json() { - return rotation.json(); - } - - public static AltosRotation fromJson(AltosJson j, AltosRotation def) { - if (j == null) - return def; - - return new AltosRotation(j); - } } diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index 93586e8c..15cf7d64 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -23,7 +23,7 @@ package org.altusmetrum.altoslib_11; import java.io.*; -public class AltosState implements Cloneable, AltosJsonable { +public class AltosState implements Cloneable { public static final int set_position = 1; public static final int set_gps = 2; @@ -46,7 +46,7 @@ public class AltosState implements Cloneable, AltosJsonable { private int prev_tick; public int boost_tick; - class AltosValue implements AltosJsonable { + class AltosValue { double value; double prev_value; private double max_value; @@ -177,28 +177,6 @@ public class AltosState implements Cloneable, AltosJsonable { prev_set_time = set_time; } - public AltosJson json() { - AltosJson j = new AltosJson(); - - j.put("value", value); - j.put("prev_value", prev_value); - j.put("max_value", max_value); - j.put("set_time", set_time); - j.put("prev_set_time", prev_set_time); - return j; - } - - AltosValue(AltosJson j) { - this(); - if (j != null) { - value = j.get_double("value", value); - prev_value = j.get_double("prev_value", prev_value); - max_value = j.get_double("max_value", max_value); - set_time = j.get_double("set_time", 0); - prev_set_time = j.get_double("prev_set_time", 0); - } - } - AltosValue() { value = AltosLib.MISSING; prev_value = AltosLib.MISSING; @@ -207,15 +185,9 @@ public class AltosState implements Cloneable, AltosJsonable { } - AltosValue AltosValue_fromJson(AltosJson j, AltosValue def) { - if (j == null) - return def; - return new AltosValue(j); - } - - class AltosCValue implements AltosJsonable { + class AltosCValue { - class AltosIValue extends AltosValue implements AltosJsonable { + class AltosIValue extends AltosValue { boolean can_max() { return c_can_max(); } @@ -223,10 +195,6 @@ public class AltosState implements Cloneable, AltosJsonable { AltosIValue() { super(); } - - AltosIValue(AltosJson j) { - super(j); - } }; public AltosIValue measured; @@ -319,25 +287,6 @@ public class AltosState implements Cloneable, AltosJsonable { measured = new AltosIValue(); computed = new AltosIValue(); } - - public AltosJson json() { - AltosJson j = new AltosJson(); - - j.put("measured", measured.json()); - j.put("computed", computed.json()); - return j; - } - - AltosCValue(AltosJson j) { - measured = new AltosIValue(j.get("measured")); - computed = new AltosIValue(j.get("computed")); - } - } - - AltosCValue AltosCValue_fromJson(AltosJson j, AltosCValue def) { - if (j == null) - return def; - return new AltosCValue(j); } private int state; @@ -389,15 +338,6 @@ public class AltosState implements Cloneable, AltosJsonable { AltosGpsGroundAltitude() { super(); } - - AltosGpsGroundAltitude (AltosJson j) { - super(j); - } - } - - AltosGpsGroundAltitude AltosGpsGroundAltitude_fromJson(AltosJson j, AltosGpsGroundAltitude def) { - if (j == null) return def; - return new AltosGpsGroundAltitude(j); } private AltosGpsGroundAltitude gps_ground_altitude; @@ -425,15 +365,6 @@ public class AltosState implements Cloneable, AltosJsonable { AltosGroundPressure () { super(); } - - AltosGroundPressure (AltosJson j) { - super(j); - } - } - - AltosGroundPressure AltosGroundPressure_fromJson(AltosJson j, AltosGroundPressure def) { - if (j == null) return def; - return new AltosGroundPressure(j); } private AltosGroundPressure ground_pressure; @@ -468,15 +399,6 @@ public class AltosState implements Cloneable, AltosJsonable { AltosAltitude() { super(); } - - AltosAltitude (AltosJson j) { - super(j); - } - } - - AltosAltitude AltosAltitude_fromJson(AltosJson j, AltosAltitude def) { - if (j == null) return def; - return new AltosAltitude(j); } private AltosAltitude altitude; @@ -501,15 +423,6 @@ public class AltosState implements Cloneable, AltosJsonable { AltosGpsAltitude() { super(); } - - AltosGpsAltitude (AltosJson j) { - super(j); - } - } - - AltosGpsAltitude AltosGpsAltitude_fromJson(AltosJson j, AltosGpsAltitude def) { - if (j == null) return def; - return new AltosGpsAltitude(j); } private AltosGpsAltitude gps_altitude; @@ -589,15 +502,6 @@ public class AltosState implements Cloneable, AltosJsonable { AltosPressure() { super(); } - - AltosPressure (AltosJson j) { - super(j); - } - } - - AltosPressure AltosPressure_fromJson(AltosJson j, AltosPressure def) { - if (j == null) return def; - return new AltosPressure(j); } private AltosPressure pressure; @@ -688,15 +592,6 @@ public class AltosState implements Cloneable, AltosJsonable { AltosSpeed() { super(); } - - AltosSpeed (AltosJson j) { - super(j); - } - } - - AltosSpeed AltosSpeed_fromJson(AltosJson j, AltosSpeed def) { - if (j == null) return def; - return new AltosSpeed(j); } private AltosSpeed speed; @@ -742,15 +637,6 @@ public class AltosState implements Cloneable, AltosJsonable { AltosAccel() { super(); } - - AltosAccel (AltosJson j) { - super(j); - } - } - - AltosAccel AltosAccel_fromJson(AltosJson j, AltosAccel def) { - if (j == null) return def; - return new AltosAccel(j); } AltosAccel acceleration; @@ -1668,222 +1554,4 @@ public class AltosState implements Cloneable, AltosJsonable { public AltosState () { init(); } - - public AltosJson json() { - AltosJson j = new AltosJson(); - - j.put("valid", true); - j.put("set", set); - j.put("received_time", received_time); - j.put("time", time); - j.put("prev_time", prev_time); - j.put("time_change", time_change); - j.put("tick", tick); - j.put("prev_tick", prev_tick); - j.put("boost_tick", boost_tick); - j.put("state", state); - j.put("flight", flight); - j.put("serial", serial); - j.put("altitude_32", altitude_32); - j.put("receiver_serial", receiver_serial); - j.put("landed", landed); - j.put("ascent", ascent); - j.put("boost", boost); - j.put("rssi", rssi); - j.put("status", status); - j.put("device_type", device_type); - j.put("config_major", config_major); - j.put("config_minor", config_minor); - j.put("apogee_delay", apogee_delay); - j.put("main_deploy", main_deploy); - j.put("flight_log_max", flight_log_max); - j.put("ground_altitude", ground_altitude); - j.put("gps_ground_altitude", gps_ground_altitude); - j.put("ground_pressure", ground_pressure); - j.put("altitude", altitude); - j.put("gps_altitude", gps_altitude); - j.put("gps_ground_speed", gps_ground_speed); - j.put("gps_ascent_rate", gps_ascent_rate); - j.put("gps_course", gps_course); - j.put("gps_speed", gps_speed); - j.put("pressure", pressure); - j.put("speed", speed); - j.put("acceleration", acceleration); - j.put("orient", orient); - j.put("kalman_height", kalman_height); - j.put("kalman_speed", kalman_speed); - j.put("kalman_acceleration", kalman_acceleration); - - j.put("battery_voltage",battery_voltage); - j.put("pyro_voltage",pyro_voltage); - j.put("temperature",temperature); - j.put("apogee_voltage",apogee_voltage); - j.put("main_voltage",main_voltage); - j.put("ignitor_voltage",ignitor_voltage); - j.put("gps", gps); - j.put("temp_gps", temp_gps); - j.put("temp_gps_sat_tick", temp_gps_sat_tick); - j.put("gps_pending", gps_pending); - j.put("gps_sequence", gps_sequence); - j.put("imu", imu); - j.put("mag", mag); - - j.put("npad", npad); - j.put("gps_waiting", gps_waiting); - j.put("gps_ready", gps_ready); - j.put("ngps", ngps); - j.put("from_pad", from_pad); - j.put("elevation", elevation); - j.put("range", range); - j.put("gps_height", gps_height); - j.put("pad_lat", pad_lat); - j.put("pad_lon", pad_lon); - j.put("pad_alt", pad_alt); - j.put("speak_tick", speak_tick); - j.put("speak_altitude", speak_altitude); - j.put("callsign", callsign); - j.put("firmware_version", firmware_version); - j.put("accel_plus_g", accel_plus_g); - j.put("accel_minus_g", accel_minus_g); - j.put("accel", accel); - j.put("ground_accel", ground_accel); - j.put("ground_accel_avg", ground_accel_avg); - j.put("log_format", log_format); - j.put("log_space", log_space); - j.put("product", product); - j.put("baro", baro); - j.put("companion", companion); - j.put("pyro_fired", pyro_fired); - j.put("accel_zero_along", accel_zero_along); - j.put("accel_zero_across", accel_zero_across); - j.put("accel_zero_through", accel_zero_through); - - j.put("rotation", rotation); - j.put("ground_rotation", ground_rotation); - - j.put("pad_orientation", pad_orientation); - - j.put("accel_ground_along", accel_ground_along); - j.put("accel_ground_across", accel_ground_across); - j.put("accel_ground_through", accel_ground_through); - - j.put("gyro_zero_roll", gyro_zero_roll); - j.put("gyro_zero_pitch", gyro_zero_pitch); - j.put("gyro_zero_yaw", gyro_zero_yaw); - - j.put("last_imu_time", last_imu_time); - return j; - } - - public AltosState(AltosJson j) { - this(); - - set = j.get_int("set", set); - received_time = j.get_long("received_time", received_time); - time = j.get_double("time", time); - prev_time = j.get_double("prev_time", prev_time); - time_change = j.get_double("time_change", time_change); - tick = j.get_int("tick", tick); - prev_tick = j.get_int("prev_tick", prev_tick); - boost_tick = j.get_int("boost_tick", boost_tick); - state = j.get_int("state", state); - flight = j.get_int("flight", flight); - serial = j.get_int("serial", serial); - altitude_32 = j.get_int("altitude_32", altitude_32); - receiver_serial = j.get_int("receiver_serial", receiver_serial); - landed = j.get_boolean("landed", landed); - ascent = j.get_boolean("ascent", ascent); - boost = j.get_boolean("boost", boost); - rssi = j.get_int("rssi", rssi); - status = j.get_int("status", status); - device_type = j.get_int("device_type", device_type); - config_major = j.get_int("config_major", config_major); - config_minor = j.get_int("config_minor", config_minor); - apogee_delay = j.get_int("apogee_delay", apogee_delay); - main_deploy = j.get_int("main_deploy", main_deploy); - flight_log_max = j.get_int("flight_log_max", flight_log_max); - ground_altitude = AltosCValue_fromJson(j.get("ground_altitude"), ground_altitude); - gps_ground_altitude = AltosGpsGroundAltitude_fromJson(j.get("gps_ground_altitude"), gps_ground_altitude); - ground_pressure = AltosGroundPressure_fromJson(j.get("ground_pressure"), ground_pressure); - altitude = AltosAltitude_fromJson(j.get("altitude"), altitude); - gps_altitude = AltosGpsAltitude_fromJson(j.get("gps_altitude"), gps_altitude); - gps_ground_speed = AltosValue_fromJson(j.get("gps_ground_speed"), gps_ground_speed); - gps_ascent_rate = AltosValue_fromJson(j.get("gps_ascent_rate"), gps_ascent_rate); - gps_course = AltosValue_fromJson(j.get("gps_course"), gps_course); - gps_speed = AltosValue_fromJson(j.get("gps_speed"), gps_speed); - pressure = AltosPressure_fromJson(j.get("pressure"), pressure); - speed = AltosSpeed_fromJson(j.get("speed"), speed); - acceleration = AltosAccel_fromJson(j.get("acceleration"), acceleration); - orient = AltosCValue_fromJson(j.get("orient"), orient); - kalman_height = AltosValue_fromJson(j.get("kalman_height"), kalman_height); - kalman_speed = AltosValue_fromJson(j.get("kalman_speed"), kalman_speed); - kalman_acceleration = AltosValue_fromJson(j.get("kalman_acceleration"), kalman_acceleration); - - battery_voltage = j.get_double("battery_voltage", battery_voltage); - pyro_voltage = j.get_double("pyro_voltage", pyro_voltage); - temperature = j.get_double("temperature", temperature); - apogee_voltage = j.get_double("apogee_voltage", apogee_voltage); - main_voltage= j.get_double("main_voltage", main_voltage); - ignitor_voltage = j.get_double_array("ignitor_voltage", ignitor_voltage); - gps = AltosGPS.fromJson(j.get("gps"), gps); - temp_gps = AltosGPS.fromJson(j.get("temp_gps"), temp_gps); - temp_gps_sat_tick = j.get_int("temp_gps_sat_tick", temp_gps_sat_tick); - gps_pending = j.get_boolean("gps_pending", gps_pending); - gps_sequence = j.get_int("gps_sequence", gps_sequence); - imu = AltosIMU.fromJson(j.get("imu"), imu); - mag = AltosMag.fromJson(j.get("mag"), mag); - - npad = j.get_int("npad", npad); - gps_waiting = j.get_int("gps_waiting", gps_waiting); - gps_ready = j.get_boolean("gps_ready", gps_ready); - ngps = j.get_int("ngps", ngps); - from_pad = AltosGreatCircle.fromJson(j.get("from_pad"), from_pad); - elevation = j.get_double("elevation", elevation); - range = j.get_double("range", range); - gps_height = j.get_double("gps_height", gps_height); - pad_lat = j.get_double("pad_lat", pad_lat); - pad_lon = j.get_double("pad_lon", pad_lon); - pad_alt = j.get_double("pad_alt", pad_alt); - speak_tick = j.get_int("speak_tick", speak_tick); - speak_altitude = j.get_double("speak_altitude", speak_altitude); - callsign = j.get_string("callsign", callsign); - firmware_version = j.get_string("firmware_version", firmware_version); - accel_plus_g = j.get_double("accel_plus_g", accel_plus_g); - accel_minus_g = j.get_double("accel_minus_g", accel_minus_g); - accel = j.get_double("accel", accel); - ground_accel = j.get_double("ground_accel", ground_accel); - ground_accel_avg = j.get_double("ground_accel_avg", ground_accel_avg); - log_format = j.get_int("log_format", log_format); - log_space = j.get_int("log_space", log_space); - product = j.get_string("product", product); - baro = AltosMs5607.fromJson(j.get("baro"), baro); - companion = AltosCompanion.fromJson(j.get("companion"), companion); - pyro_fired = j.get_int("pyro_fired", pyro_fired); - accel_zero_along = j.get_double("accel_zero_along", accel_zero_along); - accel_zero_across = j.get_double("accel_zero_across", accel_zero_across); - accel_zero_through = j.get_double("accel_zero_through", accel_zero_through); - - rotation = AltosRotation.fromJson(j.get("rotation"), rotation); - ground_rotation = AltosRotation.fromJson(j.get("ground_rotation"), ground_rotation); - - pad_orientation = j.get_int("pad_orientation", pad_orientation); - - accel_ground_along = j.get_double("accel_ground_along", accel_ground_along); - accel_ground_across = j.get_double("accel_ground_across", accel_ground_across); - accel_ground_through = j.get_double("accel_ground_through", accel_ground_through); - - gyro_zero_roll = j.get_double("gyro_zero_roll", gyro_zero_roll); - gyro_zero_pitch = j.get_double("gyro_zero_pitch", gyro_zero_pitch); - gyro_zero_yaw = j.get_double("gyro_zero_yaw", gyro_zero_yaw); - - last_imu_time = j.get_double("last_imu_time", last_imu_time); - } - - public static AltosState fromJson(AltosJson j) { - if (j == null) - return null; - if (!j.get_boolean("valid", false)) - return null; - return new AltosState(j); - } } diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 912976f9..2a9eb9c9 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -162,7 +162,6 @@ altoslib_JAVA = \ AltosMapLoader.java \ AltosMapTypeListener.java \ AltosJson.java \ - AltosJsonable.java \ AltosVersion.java JAR=altoslib_$(ALTOSLIB_VERSION).jar -- cgit v1.2.3 From a46df4f69984e3ef0064c2b211438c8d8ffaab68 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 17 Jun 2016 08:17:57 -0700 Subject: altoslib: Add construction for remaining primitive array types to JSON AltosCompanion has an array of ints, which was missed until I tried a telemetry file with companion data. Signed-off-by: Keith Packard --- altoslib/AltosJson.java | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'altoslib/AltosJson.java') diff --git a/altoslib/AltosJson.java b/altoslib/AltosJson.java index e979a459..80d83e48 100644 --- a/altoslib/AltosJson.java +++ b/altoslib/AltosJson.java @@ -1012,7 +1012,32 @@ public class AltosJson extends JsonUtil { assert_array(false); Class element_class = c.getComponentType(); - if (element_class == Double.TYPE) { + 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); -- cgit v1.2.3 From e8250fcb267a34fbbd8b88c6dcc8eec419bbcc68 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 17 Jun 2016 08:26:31 -0700 Subject: altoslib: Add back some JSON exception debugging printfs These make it possible to figure out where the JSON code went wrong. Signed-off-by: Keith Packard --- altoslib/AltosJson.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'altoslib/AltosJson.java') diff --git a/altoslib/AltosJson.java b/altoslib/AltosJson.java index 80d83e48..346144d9 100644 --- a/altoslib/AltosJson.java +++ b/altoslib/AltosJson.java @@ -1080,17 +1080,27 @@ public class AltosJson extends JsonUtil { 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; } } @@ -1223,6 +1233,8 @@ public class AltosJson extends JsonUtil { put(fieldName, json); } } catch (IllegalAccessException ie) { + System.out.printf("%s:%s %s\n", + c.getName(), fieldName, ie.toString()); } } } -- cgit v1.2.3 From 0c5a1bea3ffa7c4b6b1503733e33911cbfcb3e80 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 17 Jun 2016 08:54:19 -0700 Subject: altoslib: Stop reflective JSON class walk at Object instead of null Android has classes above Object which are all tied together which cause the object walking to fail in pretty spectacular ways. As Object has no interesting fields, that serves as a fine barrier to the super class walk and works on both android and real java. Signed-off-by: Keith Packard --- altoslib/AltosJson.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'altoslib/AltosJson.java') diff --git a/altoslib/AltosJson.java b/altoslib/AltosJson.java index 346144d9..67f3a00a 100644 --- a/altoslib/AltosJson.java +++ b/altoslib/AltosJson.java @@ -1063,7 +1063,7 @@ public class AltosJson extends JsonUtil { } else { object = c.newInstance(); } - for (; c != null; c = c.getSuperclass()) { + for (; c != Object.class; c = c.getSuperclass()) { for (Field field : c.getDeclaredFields()) { String fieldName = field.getName(); Class fieldClass = field.getType(); @@ -1208,7 +1208,7 @@ public class AltosJson extends JsonUtil { } } else { assert_hash(true); - for (Class c = object.getClass(); c != null; c = c.getSuperclass()) { + for (Class c = object.getClass(); c != Object.class; c = c.getSuperclass()) { for (Field field : c.getDeclaredFields()) { String fieldName = field.getName(); -- cgit v1.2.3