/* * Decompiled with CFR 0.152. */ package de.maxhenkel.voicechat.org.json; import de.maxhenkel.voicechat.org.json.JSONArray; import de.maxhenkel.voicechat.org.json.JSONException; import de.maxhenkel.voicechat.org.json.JSONParserConfiguration; import de.maxhenkel.voicechat.org.json.JSONPointer; import de.maxhenkel.voicechat.org.json.JSONPointerException; import de.maxhenkel.voicechat.org.json.JSONPropertyIgnore; import de.maxhenkel.voicechat.org.json.JSONPropertyName; import de.maxhenkel.voicechat.org.json.JSONString; import de.maxhenkel.voicechat.org.json.JSONTokener; import de.maxhenkel.voicechat.org.json.JSONWriter; import de.maxhenkel.voicechat.org.json.StringBuilderWriter; import java.io.Closeable; import java.io.IOException; import java.io.Writer; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.GenericArrayType; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; import java.util.Set; import java.util.regex.Pattern; public class JSONObject { static final Pattern NUMBER_PATTERN = Pattern.compile("-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?"); private final Map map; public static final Object NULL = new Null(); private static final Set EXCLUDED_RECORD_METHOD_NAMES = Collections.unmodifiableSet(new HashSet(Arrays.asList("get", "is", "set", "toString", "hashCode", "equals", "clone", "notify", "notifyAll", "wait"))); public Class getMapType() { return this.map.getClass(); } public JSONObject() { this.map = new HashMap(); } public JSONObject(JSONObject jo, String ... names) { this(names.length); for (int i = 0; i < names.length; ++i) { try { this.putOnce(names[i], jo.opt(names[i])); continue; } catch (Exception exception) { // empty catch block } } } public JSONObject(JSONTokener x) throws JSONException { this(x, x.getJsonParserConfiguration()); } public JSONObject(JSONTokener x, JSONParserConfiguration jsonParserConfiguration) throws JSONException { this(); boolean isInitial; boolean bl = isInitial = x.getPrevious() == '\u0000'; if (x.nextClean() != '{') { throw x.syntaxError("A JSONObject text must begin with '{'"); } while (!this.parseJSONObject(x, jsonParserConfiguration, isInitial)) { } } private boolean parseJSONObject(JSONTokener jsonTokener, JSONParserConfiguration jsonParserConfiguration, boolean isInitial) { boolean doneParsing = false; char c = jsonTokener.nextClean(); switch (c) { case '\u0000': { throw jsonTokener.syntaxError("A JSONObject text must end with '}'"); } case '}': { if (isInitial && jsonParserConfiguration.isStrictMode() && jsonTokener.nextClean() != '\u0000') { throw jsonTokener.syntaxError("Strict mode error: Unparsed characters found at end of input text"); } return true; } } Object obj = jsonTokener.nextSimpleValue(c); String key = obj.toString(); JSONObject.checkKeyForStrictMode(jsonTokener, jsonParserConfiguration, obj); c = jsonTokener.nextClean(); if (c != ':') { throw jsonTokener.syntaxError("Expected a ':' after a key"); } if (key != null) { boolean keyExists; boolean bl = keyExists = this.opt(key) != null; if (keyExists && !jsonParserConfiguration.isOverwriteDuplicateKey()) { throw jsonTokener.syntaxError("Duplicate key \"" + key + "\""); } Object value = jsonTokener.nextValue(); if (value != null) { this.put(key, value); } } if (JSONObject.parseEndOfKeyValuePair(jsonTokener, jsonParserConfiguration, isInitial)) { doneParsing = true; } return doneParsing; } private static boolean parseEndOfKeyValuePair(JSONTokener jsonTokener, JSONParserConfiguration jsonParserConfiguration, boolean isInitial) { switch (jsonTokener.nextClean()) { case ';': { if (!jsonParserConfiguration.isStrictMode()) break; throw jsonTokener.syntaxError("Strict mode error: Invalid character ';' found"); } case ',': { if (jsonTokener.nextClean() == '}') { if (jsonParserConfiguration.isStrictMode()) { throw jsonTokener.syntaxError("Strict mode error: Expected another object element"); } return true; } if (jsonTokener.end()) { throw jsonTokener.syntaxError("A JSONObject text must end with '}'"); } jsonTokener.back(); break; } case '}': { if (isInitial && jsonParserConfiguration.isStrictMode() && jsonTokener.nextClean() != '\u0000') { throw jsonTokener.syntaxError("Strict mode error: Unparsed characters found at end of input text"); } return true; } default: { throw jsonTokener.syntaxError("Expected a ',' or '}'"); } } return false; } private static void checkKeyForStrictMode(JSONTokener jsonTokener, JSONParserConfiguration jsonParserConfiguration, Object obj) { if (jsonParserConfiguration != null && jsonParserConfiguration.isStrictMode()) { if (obj instanceof Boolean) { throw jsonTokener.syntaxError(String.format("Strict mode error: key '%s' cannot be boolean", obj.toString())); } if (obj == NULL) { throw jsonTokener.syntaxError(String.format("Strict mode error: key '%s' cannot be null", obj.toString())); } if (obj instanceof Number) { throw jsonTokener.syntaxError(String.format("Strict mode error: key '%s' cannot be number", obj.toString())); } } } public JSONObject(Map m) { this(m, 0, new JSONParserConfiguration()); } public JSONObject(Map m, JSONParserConfiguration jsonParserConfiguration) { this(m, 0, jsonParserConfiguration); } private JSONObject(Map m, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { if (recursionDepth > jsonParserConfiguration.getMaxNestingDepth()) { throw new JSONException("JSONObject has reached recursion depth limit of " + jsonParserConfiguration.getMaxNestingDepth()); } if (m == null) { this.map = new HashMap(); } else { this.map = new HashMap(m.size()); for (Map.Entry e : m.entrySet()) { if (e.getKey() == null) { throw new NullPointerException("Null key."); } Object value = e.getValue(); if (value == null && !jsonParserConfiguration.isUseNativeNulls()) continue; JSONObject.testValidity(value); this.map.put(String.valueOf(e.getKey()), JSONObject.wrap(value, recursionDepth + 1, jsonParserConfiguration)); } } } public JSONObject(Object bean) { this(); this.populateMap(bean, new JSONParserConfiguration()); } public JSONObject(Object bean, JSONParserConfiguration jsonParserConfiguration) { this(); this.populateMap(bean, jsonParserConfiguration); } private JSONObject(Object bean, Set objectsRecord) { this(); this.populateMap(bean, objectsRecord, new JSONParserConfiguration()); } public JSONObject(Object object, String ... names) { this(names.length); Class c = object.getClass(); for (int i = 0; i < names.length; ++i) { String name = names[i]; try { this.putOpt(name, c.getField(name).get(object)); continue; } catch (Exception exception) { // empty catch block } } } public JSONObject(String source) throws JSONException { this(source, new JSONParserConfiguration()); } public JSONObject(String source, JSONParserConfiguration jsonParserConfiguration) throws JSONException { this(new JSONTokener(source, jsonParserConfiguration), jsonParserConfiguration); } public JSONObject(String baseName, Locale locale) throws JSONException { this(); ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale, Thread.currentThread().getContextClassLoader()); Enumeration keys = bundle.getKeys(); while (keys.hasMoreElements()) { String key = keys.nextElement(); if (key == null) continue; String[] path = key.split("\\."); int last = path.length - 1; JSONObject target = this; for (int i = 0; i < last; ++i) { String segment = path[i]; JSONObject nextTarget = target.optJSONObject(segment); if (nextTarget == null) { nextTarget = new JSONObject(); target.put(segment, nextTarget); } target = nextTarget; } target.put(path[last], bundle.getString(key)); } } protected JSONObject(int initialCapacity) { this.map = new HashMap(initialCapacity); } public JSONObject accumulate(String key, Object value) throws JSONException { JSONObject.testValidity(value); Object object = this.opt(key); if (object == null) { this.put(key, value instanceof JSONArray ? new JSONArray().put(value) : value); } else if (object instanceof JSONArray) { ((JSONArray)object).put(value); } else { this.put(key, new JSONArray().put(object).put(value)); } return this; } public JSONObject append(String key, Object value) throws JSONException { JSONObject.testValidity(value); Object object = this.opt(key); if (object == null) { this.put(key, new JSONArray().put(value)); } else if (object instanceof JSONArray) { this.put(key, ((JSONArray)object).put(value)); } else { throw JSONObject.wrongValueFormatException(key, "JSONArray", null, null); } return this; } public static String doubleToString(double d) { if (Double.isInfinite(d) || Double.isNaN(d)) { return "null"; } String string = Double.toString(d); if (string.indexOf(46) > 0 && string.indexOf(101) < 0 && string.indexOf(69) < 0) { while (string.endsWith("0")) { string = string.substring(0, string.length() - 1); } if (string.endsWith(".")) { string = string.substring(0, string.length() - 1); } } return string; } public Object get(String key) throws JSONException { if (key == null) { throw new JSONException("Null key."); } Object object = this.opt(key); if (object == null) { throw new JSONException("JSONObject[" + JSONObject.quote(key) + "] not found."); } return object; } public > E getEnum(Class clazz, String key) throws JSONException { E val = this.optEnum(clazz, key); if (val == null) { throw JSONObject.wrongValueFormatException(key, "enum of type " + JSONObject.quote(clazz.getSimpleName()), this.opt(key), null); } return val; } public boolean getBoolean(String key) throws JSONException { Object object = this.get(key); if (Boolean.FALSE.equals(object) || object instanceof String && "false".equalsIgnoreCase((String)object)) { return false; } if (Boolean.TRUE.equals(object) || object instanceof String && "true".equalsIgnoreCase((String)object)) { return true; } throw JSONObject.wrongValueFormatException(key, "Boolean", object, null); } public BigInteger getBigInteger(String key) throws JSONException { Object object = this.get(key); BigInteger ret = JSONObject.objectToBigInteger(object, null); if (ret != null) { return ret; } throw JSONObject.wrongValueFormatException(key, "BigInteger", object, null); } public BigDecimal getBigDecimal(String key) throws JSONException { Object object = this.get(key); BigDecimal ret = JSONObject.objectToBigDecimal(object, null); if (ret != null) { return ret; } throw JSONObject.wrongValueFormatException(key, "BigDecimal", object, null); } public double getDouble(String key) throws JSONException { Object object = this.get(key); if (object instanceof Number) { return ((Number)object).doubleValue(); } try { return Double.parseDouble(object.toString()); } catch (Exception e) { throw JSONObject.wrongValueFormatException(key, "double", object, e); } } public float getFloat(String key) throws JSONException { Object object = this.get(key); if (object instanceof Number) { return ((Number)object).floatValue(); } try { return Float.parseFloat(object.toString()); } catch (Exception e) { throw JSONObject.wrongValueFormatException(key, "float", object, e); } } public Number getNumber(String key) throws JSONException { Object object = this.get(key); try { if (object instanceof Number) { return (Number)object; } return JSONObject.stringToNumber(object.toString()); } catch (Exception e) { throw JSONObject.wrongValueFormatException(key, "number", object, e); } } public int getInt(String key) throws JSONException { Object object = this.get(key); if (object instanceof Number) { return ((Number)object).intValue(); } try { return Integer.parseInt(object.toString()); } catch (Exception e) { throw JSONObject.wrongValueFormatException(key, "int", object, e); } } public JSONArray getJSONArray(String key) throws JSONException { Object object = this.get(key); if (object instanceof JSONArray) { return (JSONArray)object; } throw JSONObject.wrongValueFormatException(key, "JSONArray", object, null); } public JSONObject getJSONObject(String key) throws JSONException { Object object = this.get(key); if (object instanceof JSONObject) { return (JSONObject)object; } throw JSONObject.wrongValueFormatException(key, "JSONObject", object, null); } public long getLong(String key) throws JSONException { Object object = this.get(key); if (object instanceof Number) { return ((Number)object).longValue(); } try { return Long.parseLong(object.toString()); } catch (Exception e) { throw JSONObject.wrongValueFormatException(key, "long", object, e); } } public static String[] getNames(JSONObject jo) { if (jo.isEmpty()) { return null; } return jo.keySet().toArray(new String[jo.length()]); } public static String[] getNames(Object object) { if (object == null) { return null; } Class klass = object.getClass(); Field[] fields = klass.getFields(); int length = fields.length; if (length == 0) { return null; } String[] names = new String[length]; for (int i = 0; i < length; ++i) { names[i] = fields[i].getName(); } return names; } public String getString(String key) throws JSONException { Object object = this.get(key); if (object instanceof String) { return (String)object; } throw JSONObject.wrongValueFormatException(key, "string", object, null); } public boolean has(String key) { return this.map.containsKey(key); } public JSONObject increment(String key) throws JSONException { Object value = this.opt(key); if (value == null) { this.put(key, 1); } else if (value instanceof Integer) { this.put(key, (Integer)value + 1); } else if (value instanceof Long) { this.put(key, (Long)value + 1L); } else if (value instanceof BigInteger) { this.put(key, ((BigInteger)value).add(BigInteger.ONE)); } else if (value instanceof Float) { this.put(key, ((Float)value).floatValue() + 1.0f); } else if (value instanceof Double) { this.put(key, (Double)value + 1.0); } else if (value instanceof BigDecimal) { this.put(key, ((BigDecimal)value).add(BigDecimal.ONE)); } else { throw new JSONException("Unable to increment [" + JSONObject.quote(key) + "]."); } return this; } public boolean isNull(String key) { return NULL.equals(this.opt(key)); } public Iterator keys() { return this.keySet().iterator(); } public Set keySet() { return this.map.keySet(); } protected Set> entrySet() { return this.map.entrySet(); } public int length() { return this.map.size(); } public void clear() { this.map.clear(); } public boolean isEmpty() { return this.map.isEmpty(); } public JSONArray names() { if (this.map.isEmpty()) { return null; } return new JSONArray((Collection)this.map.keySet()); } public static String numberToString(Number number) throws JSONException { if (number == null) { throw new JSONException("Null pointer"); } JSONObject.testValidity(number); String string = number.toString(); if (string.indexOf(46) > 0 && string.indexOf(101) < 0 && string.indexOf(69) < 0) { while (string.endsWith("0")) { string = string.substring(0, string.length() - 1); } if (string.endsWith(".")) { string = string.substring(0, string.length() - 1); } } return string; } public Object opt(String key) { return key == null ? null : this.map.get(key); } public > E optEnum(Class clazz, String key) { return this.optEnum(clazz, key, null); } public > E optEnum(Class clazz, String key, E defaultValue) { try { Object val = this.opt(key); if (NULL.equals(val)) { return defaultValue; } if (clazz.isAssignableFrom(val.getClass())) { Enum myE = (Enum)val; return (E)myE; } return Enum.valueOf(clazz, val.toString()); } catch (IllegalArgumentException e) { return defaultValue; } catch (NullPointerException e) { return defaultValue; } } public boolean optBoolean(String key) { return this.optBoolean(key, false); } public boolean optBoolean(String key, boolean defaultValue) { Object val = this.opt(key); if (NULL.equals(val)) { return defaultValue; } if (val instanceof Boolean) { return (Boolean)val; } try { return this.getBoolean(key); } catch (Exception e) { return defaultValue; } } public Boolean optBooleanObject(String key) { return this.optBooleanObject(key, false); } public Boolean optBooleanObject(String key, Boolean defaultValue) { Object val = this.opt(key); if (NULL.equals(val)) { return defaultValue; } if (val instanceof Boolean) { return (boolean)((Boolean)val); } try { return this.getBoolean(key); } catch (Exception e) { return defaultValue; } } public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) { Object val = this.opt(key); return JSONObject.objectToBigDecimal(val, defaultValue); } static BigDecimal objectToBigDecimal(Object val, BigDecimal defaultValue) { return JSONObject.objectToBigDecimal(val, defaultValue, true); } static BigDecimal objectToBigDecimal(Object val, BigDecimal defaultValue, boolean exact) { if (NULL.equals(val)) { return defaultValue; } if (val instanceof BigDecimal) { return (BigDecimal)val; } if (val instanceof BigInteger) { return new BigDecimal((BigInteger)val); } if (val instanceof Double || val instanceof Float) { if (!JSONObject.numberIsFinite((Number)val)) { return defaultValue; } if (exact) { return new BigDecimal(((Number)val).doubleValue()); } return new BigDecimal(val.toString()); } if (val instanceof Long || val instanceof Integer || val instanceof Short || val instanceof Byte) { return new BigDecimal(((Number)val).longValue()); } try { return new BigDecimal(val.toString()); } catch (Exception e) { return defaultValue; } } public BigInteger optBigInteger(String key, BigInteger defaultValue) { Object val = this.opt(key); return JSONObject.objectToBigInteger(val, defaultValue); } static BigInteger objectToBigInteger(Object val, BigInteger defaultValue) { if (NULL.equals(val)) { return defaultValue; } if (val instanceof BigInteger) { return (BigInteger)val; } if (val instanceof BigDecimal) { return ((BigDecimal)val).toBigInteger(); } if (val instanceof Double || val instanceof Float) { if (!JSONObject.numberIsFinite((Number)val)) { return defaultValue; } return BigDecimal.valueOf(((Number)val).doubleValue()).toBigInteger(); } if (val instanceof Long || val instanceof Integer || val instanceof Short || val instanceof Byte) { return BigInteger.valueOf(((Number)val).longValue()); } try { String valStr = val.toString(); if (JSONObject.isDecimalNotation(valStr)) { return new BigDecimal(valStr).toBigInteger(); } return new BigInteger(valStr); } catch (Exception e) { return defaultValue; } } public double optDouble(String key) { return this.optDouble(key, Double.NaN); } public double optDouble(String key, double defaultValue) { Number val = this.optNumber(key); if (val == null) { return defaultValue; } return val.doubleValue(); } public Double optDoubleObject(String key) { return this.optDoubleObject(key, Double.NaN); } public Double optDoubleObject(String key, Double defaultValue) { Number val = this.optNumber(key); if (val == null) { return defaultValue; } return val.doubleValue(); } public float optFloat(String key) { return this.optFloat(key, Float.NaN); } public float optFloat(String key, float defaultValue) { Number val = this.optNumber(key); if (val == null) { return defaultValue; } return val.floatValue(); } public Float optFloatObject(String key) { return this.optFloatObject(key, Float.valueOf(Float.NaN)); } public Float optFloatObject(String key, Float defaultValue) { Number val = this.optNumber(key); if (val == null) { return defaultValue; } return Float.valueOf(val.floatValue()); } public int optInt(String key) { return this.optInt(key, 0); } public int optInt(String key, int defaultValue) { Number val = this.optNumber(key, null); if (val == null) { return defaultValue; } return val.intValue(); } public Integer optIntegerObject(String key) { return this.optIntegerObject(key, 0); } public Integer optIntegerObject(String key, Integer defaultValue) { Number val = this.optNumber(key, null); if (val == null) { return defaultValue; } return val.intValue(); } public JSONArray optJSONArray(String key) { return this.optJSONArray(key, null); } public JSONArray optJSONArray(String key, JSONArray defaultValue) { Object object = this.opt(key); return object instanceof JSONArray ? (JSONArray)object : defaultValue; } public JSONObject optJSONObject(String key) { return this.optJSONObject(key, null); } public JSONObject optJSONObject(String key, JSONObject defaultValue) { Object object = this.opt(key); return object instanceof JSONObject ? (JSONObject)object : defaultValue; } public long optLong(String key) { return this.optLong(key, 0L); } public long optLong(String key, long defaultValue) { Number val = this.optNumber(key, null); if (val == null) { return defaultValue; } return val.longValue(); } public Long optLongObject(String key) { return this.optLongObject(key, 0L); } public Long optLongObject(String key, Long defaultValue) { Number val = this.optNumber(key, null); if (val == null) { return defaultValue; } return val.longValue(); } public Number optNumber(String key) { return this.optNumber(key, null); } public Number optNumber(String key, Number defaultValue) { Object val = this.opt(key); if (NULL.equals(val)) { return defaultValue; } if (val instanceof Number) { return (Number)val; } try { return JSONObject.stringToNumber(val.toString()); } catch (Exception e) { return defaultValue; } } public String optString(String key) { return this.optString(key, ""); } public String optString(String key, String defaultValue) { Object object = this.opt(key); return NULL.equals(object) ? defaultValue : object.toString(); } private void populateMap(Object bean, JSONParserConfiguration jsonParserConfiguration) { this.populateMap(bean, Collections.newSetFromMap(new IdentityHashMap()), jsonParserConfiguration); } private void populateMap(Object bean, Set objectsRecord, JSONParserConfiguration jsonParserConfiguration) { Method[] methods; Class klass = bean.getClass(); boolean isRecord = JSONObject.isRecordType(klass); for (Method method : methods = JSONObject.getMethods(klass)) { String key; if (!JSONObject.isValidMethod(method) || (key = JSONObject.getKeyNameFromMethod(method, isRecord)) == null || key.isEmpty()) continue; this.processMethod(bean, objectsRecord, jsonParserConfiguration, method, key); } } private void processMethod(Object bean, Set objectsRecord, JSONParserConfiguration jsonParserConfiguration, Method method, String key) { try { Object result = method.invoke(bean, new Object[0]); if (result != null || jsonParserConfiguration.isUseNativeNulls()) { if (objectsRecord.contains(result)) { throw JSONObject.recursivelyDefinedObjectException(key); } objectsRecord.add(result); JSONObject.testValidity(result); this.map.put(key, JSONObject.wrap(result, objectsRecord)); objectsRecord.remove(result); JSONObject.closeClosable(result); } } catch (IllegalAccessException illegalAccessException) { } catch (IllegalArgumentException illegalArgumentException) { } catch (InvocationTargetException invocationTargetException) { // empty catch block } } private static boolean isRecordType(Class klass) { try { Method isRecordMethod = Class.class.getMethod("isRecord", new Class[0]); return (Boolean)isRecordMethod.invoke(klass, new Object[0]); } catch (NoSuchMethodException e) { return false; } catch (Exception e) { return false; } } private static Method[] getMethods(Class klass) { boolean includeSuperClass = klass.getClassLoader() != null; return includeSuperClass ? klass.getMethods() : klass.getDeclaredMethods(); } private static boolean isValidMethodName(String name) { return !"getClass".equals(name) && !"getDeclaringClass".equals(name); } private static String getKeyNameFromMethod(Method method, boolean isRecordType) { String key; int forcedNameDepth; int ignoreDepth = JSONObject.getAnnotationDepth(method, JSONPropertyIgnore.class); if (ignoreDepth > 0 && ((forcedNameDepth = JSONObject.getAnnotationDepth(method, JSONPropertyName.class)) < 0 || ignoreDepth <= forcedNameDepth)) { return null; } JSONPropertyName annotation = JSONObject.getAnnotation(method, JSONPropertyName.class); if (JSONObject.annotationValueNotEmpty(annotation)) { return annotation.value(); } String name = method.getName(); if (name.startsWith("get") && name.length() > 3) { key = name.substring(3); } else if (name.startsWith("is") && name.length() > 2) { key = name.substring(2); } else { if (isRecordType && JSONObject.isRecordStyleAccessor(name, method)) { return name; } return null; } if (key.isEmpty() || Character.isLowerCase(key.charAt(0))) { return null; } if (key.length() == 1) { key = key.toLowerCase(Locale.ROOT); } else if (!Character.isUpperCase(key.charAt(1))) { key = key.substring(0, 1).toLowerCase(Locale.ROOT) + key.substring(1); } return key; } private static boolean isRecordStyleAccessor(String methodName, Method method) { if (methodName.isEmpty() || !Character.isLowerCase(methodName.charAt(0))) { return false; } if (EXCLUDED_RECORD_METHOD_NAMES.contains(methodName)) { return false; } Class declaringClass = method.getDeclaringClass(); if (declaringClass == null || declaringClass == Object.class) { return false; } if (Enum.class.isAssignableFrom(declaringClass) || Number.class.isAssignableFrom(declaringClass)) { return false; } String className = declaringClass.getName(); return !className.startsWith("java.") && !className.startsWith("javax."); } private static boolean annotationValueNotEmpty(JSONPropertyName annotation) { return annotation != null && annotation.value() != null && !annotation.value().isEmpty(); } private static boolean isValidMethod(Method method) { int modifiers = method.getModifiers(); return Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers) && method.getParameterTypes().length == 0 && !method.isBridge() && method.getReturnType() != Void.TYPE && JSONObject.isValidMethodName(method.getName()); } private static void closeClosable(Object input) { if (input instanceof Closeable) { try { ((Closeable)input).close(); } catch (IOException iOException) { // empty catch block } } } private static A getAnnotation(Method m, Class annotationClass) { if (m == null || annotationClass == null) { return null; } if (m.isAnnotationPresent(annotationClass)) { return m.getAnnotation(annotationClass); } Class c = m.getDeclaringClass(); if (c.getSuperclass() == null) { return null; } for (Class i : c.getInterfaces()) { try { Method im = i.getMethod(m.getName(), m.getParameterTypes()); return JSONObject.getAnnotation(im, annotationClass); } catch (SecurityException securityException) { } catch (NoSuchMethodException noSuchMethodException) { // empty catch block } } if (Object.class.equals(c.getSuperclass())) { return null; } try { return JSONObject.getAnnotation(c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()), annotationClass); } catch (SecurityException ex) { return null; } catch (NoSuchMethodException ex) { return null; } } private static int getAnnotationDepth(Method m, Class annotationClass) { if (m == null || annotationClass == null) { return -1; } if (m.isAnnotationPresent(annotationClass)) { return 1; } Class c = m.getDeclaringClass(); if (c.getSuperclass() == null) { return -1; } for (Class i : c.getInterfaces()) { try { Method im = i.getMethod(m.getName(), m.getParameterTypes()); int d = JSONObject.getAnnotationDepth(im, annotationClass); if (d <= 0) continue; return d + 1; } catch (SecurityException securityException) { } catch (NoSuchMethodException noSuchMethodException) { // empty catch block } } if (Object.class.equals(c.getSuperclass())) { return -1; } try { int d = JSONObject.getAnnotationDepth(c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()), annotationClass); if (d > 0) { return d + 1; } return -1; } catch (SecurityException ex) { return -1; } catch (NoSuchMethodException ex) { return -1; } } public JSONObject put(String key, boolean value) throws JSONException { return this.put(key, value ? Boolean.TRUE : Boolean.FALSE); } public JSONObject put(String key, Collection value) throws JSONException { return this.put(key, new JSONArray(value)); } public JSONObject put(String key, double value) throws JSONException { return this.put(key, (Object)value); } public JSONObject put(String key, float value) throws JSONException { return this.put(key, Float.valueOf(value)); } public JSONObject put(String key, int value) throws JSONException { return this.put(key, (Object)value); } public JSONObject put(String key, long value) throws JSONException { return this.put(key, (Object)value); } public JSONObject put(String key, Map value) throws JSONException { return this.put(key, new JSONObject(value)); } public JSONObject put(String key, Object value) throws JSONException { if (key == null) { throw new NullPointerException("Null key."); } if (value != null) { JSONObject.testValidity(value); this.map.put(key, value); } else { this.remove(key); } return this; } public JSONObject putOnce(String key, Object value) throws JSONException { if (key != null && value != null) { if (this.opt(key) != null) { throw new JSONException("Duplicate key \"" + key + "\""); } return this.put(key, value); } return this; } public JSONObject putOpt(String key, Object value) throws JSONException { if (key != null && value != null) { return this.put(key, value); } return this; } public Object query(String jsonPointer) { return this.query(new JSONPointer(jsonPointer)); } public Object query(JSONPointer jsonPointer) { return jsonPointer.queryFrom(this); } public Object optQuery(String jsonPointer) { return this.optQuery(new JSONPointer(jsonPointer)); } public Object optQuery(JSONPointer jsonPointer) { try { return jsonPointer.queryFrom(this); } catch (JSONPointerException e) { return null; } } public static String quote(String string) { if (string == null || string.isEmpty()) { return "\"\""; } StringBuilderWriter sw = new StringBuilderWriter(string.length() + 2); try { return JSONObject.quote(string, sw).toString(); } catch (IOException ignored) { return ""; } } public static Writer quote(String string, Writer w) throws IOException { if (string == null || string.isEmpty()) { w.write("\"\""); return w; } char c = '\u0000'; int len = string.length(); w.write(34); block9: for (int i = 0; i < len; ++i) { char b = c; c = string.charAt(i); switch (c) { case '\"': case '\\': { w.write(92); w.write(c); continue block9; } case '/': { if (b == '<') { w.write(92); } w.write(c); continue block9; } case '\b': { w.write("\\b"); continue block9; } case '\t': { w.write("\\t"); continue block9; } case '\n': { w.write("\\n"); continue block9; } case '\f': { w.write("\\f"); continue block9; } case '\r': { w.write("\\r"); continue block9; } default: { JSONObject.writeAsHex(w, c); } } } w.write(34); return w; } private static void writeAsHex(Writer w, char c) throws IOException { if (c < ' ' || c >= '\u0080' && c < '\u00a0' || c >= '\u2000' && c < '\u2100') { w.write("\\u"); String hhhh = Integer.toHexString(c); w.write("0000", 0, 4 - hhhh.length()); w.write(hhhh); } else { w.write(c); } } public Object remove(String key) { return this.map.remove(key); } public boolean similar(Object other) { try { if (!(other instanceof JSONObject)) { return false; } if (!this.keySet().equals(((JSONObject)other).keySet())) { return false; } return this.checkSimilarEntries(other); } catch (Exception e) { return false; } } private boolean checkSimilarEntries(Object other) { for (Map.Entry entry : this.entrySet()) { Object valueOther; String name = entry.getKey(); Object valueThis = entry.getValue(); if (valueThis == (valueOther = ((JSONObject)other).get(name))) continue; if (valueThis == null) { return false; } if (this.checkObjectType(valueThis, valueOther)) continue; return false; } return true; } private boolean checkObjectType(Object valueThis, Object valueOther) { if (valueThis instanceof JSONObject) { return ((JSONObject)valueThis).similar(valueOther); } if (valueThis instanceof JSONArray) { return ((JSONArray)valueThis).similar(valueOther); } if (valueThis instanceof Number && valueOther instanceof Number) { return JSONObject.isNumberSimilar((Number)valueThis, (Number)valueOther); } if (valueThis instanceof JSONString && valueOther instanceof JSONString) { return ((JSONString)valueThis).toJSONString().equals(((JSONString)valueOther).toJSONString()); } return valueThis.equals(valueOther); } static boolean isNumberSimilar(Number l, Number r) { if (!JSONObject.numberIsFinite(l) || !JSONObject.numberIsFinite(r)) { return false; } if (l.getClass().equals(r.getClass()) && l instanceof Comparable) { int compareTo = ((Comparable)((Object)l)).compareTo(r); return compareTo == 0; } BigDecimal lBigDecimal = JSONObject.objectToBigDecimal(l, null, false); BigDecimal rBigDecimal = JSONObject.objectToBigDecimal(r, null, false); if (lBigDecimal == null || rBigDecimal == null) { return false; } return lBigDecimal.compareTo(rBigDecimal) == 0; } private static boolean numberIsFinite(Number n) { if (n instanceof Double && (((Double)n).isInfinite() || ((Double)n).isNaN())) { return false; } return !(n instanceof Float) || !((Float)n).isInfinite() && !((Float)n).isNaN(); } protected static boolean isDecimalNotation(String val) { return val.indexOf(46) > -1 || val.indexOf(101) > -1 || val.indexOf(69) > -1 || "-0".equals(val); } public static Object stringToValue(String string) { if ("".equals(string)) { return string; } if ("true".equalsIgnoreCase(string)) { return Boolean.TRUE; } if ("false".equalsIgnoreCase(string)) { return Boolean.FALSE; } if ("null".equalsIgnoreCase(string)) { return NULL; } char initial = string.charAt(0); if (initial >= '0' && initial <= '9' || initial == '-') { try { return JSONObject.stringToNumber(string); } catch (Exception exception) { // empty catch block } } return string; } protected static Number stringToNumber(String val) throws NumberFormatException { char initial = val.charAt(0); if (initial >= '0' && initial <= '9' || initial == '-') { if (JSONObject.isDecimalNotation(val)) { return JSONObject.getNumber(val, initial); } JSONObject.checkForInvalidNumberFormat(val, initial); BigInteger bi = new BigInteger(val); if (bi.bitLength() <= 31) { return bi.intValue(); } if (bi.bitLength() <= 63) { return bi.longValue(); } return bi; } throw new NumberFormatException("val [" + val + "] is not a valid number."); } private static void checkForInvalidNumberFormat(String val, char initial) { if (initial == '0' && val.length() > 1) { char at1 = val.charAt(1); if (at1 >= '0' && at1 <= '9') { throw new NumberFormatException("val [" + val + "] is not a valid number."); } } else if (initial == '-' && val.length() > 2) { char at1 = val.charAt(1); char at2 = val.charAt(2); if (at1 == '0' && at2 >= '0' && at2 <= '9') { throw new NumberFormatException("val [" + val + "] is not a valid number."); } } } private static Number getNumber(String val, char initial) { try { BigDecimal bd = new BigDecimal(val); if (initial == '-' && BigDecimal.ZERO.compareTo(bd) == 0) { return -0.0; } return bd; } catch (NumberFormatException retryAsDouble) { try { Double d = Double.valueOf(val); if (d.isNaN() || d.isInfinite()) { throw new NumberFormatException("val [" + val + "] is not a valid number."); } return d; } catch (NumberFormatException ignore) { throw new NumberFormatException("val [" + val + "] is not a valid number."); } } } public static void testValidity(Object o) throws JSONException { if (o instanceof Number && !JSONObject.numberIsFinite((Number)o)) { throw new JSONException("JSON does not allow non-finite numbers."); } } public JSONArray toJSONArray(JSONArray names) throws JSONException { if (names == null || names.isEmpty()) { return null; } JSONArray ja = new JSONArray(); for (int i = 0; i < names.length(); ++i) { ja.put(this.opt(names.getString(i))); } return ja; } public String toString() { try { return this.toString(0); } catch (Exception e) { return null; } } public String toString(int indentFactor) throws JSONException { int initialSize = this.map.size() * 6; StringBuilderWriter w = new StringBuilderWriter(Math.max(initialSize, 16)); return this.write(w, indentFactor, 0).toString(); } public static String valueToString(Object value) throws JSONException { return JSONWriter.valueToString(value); } public static Object wrap(Object object) { return JSONObject.wrap(object, null); } static Object wrap(Object object, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { return JSONObject.wrap(object, null, recursionDepth, jsonParserConfiguration); } private static Object wrap(Object object, Set objectsRecord) { return JSONObject.wrap(object, objectsRecord, 0, new JSONParserConfiguration()); } private static Object wrap(Object object, Set objectsRecord, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { try { String objectPackageName; if (NULL.equals(object)) { return NULL; } if (object instanceof JSONObject || object instanceof JSONArray || object instanceof JSONString || object instanceof String || object instanceof Byte || object instanceof Character || object instanceof Short || object instanceof Integer || object instanceof Long || object instanceof Boolean || object instanceof Float || object instanceof Double || object instanceof BigInteger || object instanceof BigDecimal || object instanceof Enum) { return object; } if (object instanceof Collection) { Collection coll = (Collection)object; return new JSONArray(coll, recursionDepth, jsonParserConfiguration); } if (object.getClass().isArray()) { return new JSONArray(object); } if (object instanceof Map) { Map map = (Map)object; return new JSONObject(map, recursionDepth, jsonParserConfiguration); } Package objectPackage = object.getClass().getPackage(); String string = objectPackageName = objectPackage != null ? objectPackage.getName() : ""; if (objectPackageName.startsWith("java.") || objectPackageName.startsWith("javax.") || object.getClass().getClassLoader() == null) { return object.toString(); } if (objectsRecord != null) { return new JSONObject(object, objectsRecord); } return new JSONObject(object); } catch (JSONException exception) { throw exception; } catch (Exception exception) { return null; } } public Writer write(Writer writer) throws JSONException { return this.write(writer, 0, 0); } static final Writer writeValue(Writer writer, Object value, int indentFactor, int indent) throws JSONException, IOException { if (value == null || value.equals(null)) { writer.write("null"); } else if (value instanceof JSONString) { JSONObject.processJsonStringToWriteValue(writer, value); } else { if (value instanceof String) { JSONObject.quote(value.toString(), writer); return writer; } if (value instanceof Number) { JSONObject.processNumberToWriteValue(writer, (Number)value); } else if (value instanceof Boolean) { writer.write(value.toString()); } else if (value instanceof Enum) { writer.write(JSONObject.quote(((Enum)value).name())); } else if (value instanceof JSONObject) { ((JSONObject)value).write(writer, indentFactor, indent); } else if (value instanceof JSONArray) { ((JSONArray)value).write(writer, indentFactor, indent); } else if (value instanceof Map) { Map map = (Map)value; new JSONObject(map).write(writer, indentFactor, indent); } else if (value instanceof Collection) { Collection coll = (Collection)value; new JSONArray(coll).write(writer, indentFactor, indent); } else if (value.getClass().isArray()) { new JSONArray(value).write(writer, indentFactor, indent); } else { JSONObject.quote(value.toString(), writer); } } return writer; } private static void processJsonStringToWriteValue(Writer writer, Object value) throws IOException { String o; try { o = ((JSONString)value).toJSONString(); } catch (Exception e) { throw new JSONException(e); } writer.write(o != null ? o.toString() : JSONObject.quote(value.toString())); } private static void processNumberToWriteValue(Writer writer, Number value) throws IOException { String numberAsString = JSONObject.numberToString(value); if (NUMBER_PATTERN.matcher(numberAsString).matches()) { writer.write(numberAsString); } else { JSONObject.quote(numberAsString, writer); } } static final void indent(Writer writer, int indent) throws IOException { for (int i = 0; i < indent; ++i) { writer.write(32); } } public Writer write(Writer writer, int indentFactor, int indent) throws JSONException { try { boolean needsComma = false; int length = this.length(); writer.write(123); if (length == 1) { Map.Entry entry = this.entrySet().iterator().next(); String key = entry.getKey(); writer.write(JSONObject.quote(key)); writer.write(58); if (indentFactor > 0) { writer.write(32); } JSONObject.attemptWriteValue(writer, indentFactor, indent, entry, key); } else if (length != 0) { this.writeContent(writer, indentFactor, indent, needsComma); } writer.write(125); return writer; } catch (IOException exception) { throw new JSONException(exception); } } private void writeContent(Writer writer, int indentFactor, int indent, boolean needsComma) throws IOException { int newIndent = indent + indentFactor; for (Map.Entry entry : this.entrySet()) { if (needsComma) { writer.write(44); } if (indentFactor > 0) { writer.write(10); } JSONObject.indent(writer, newIndent); String key = entry.getKey(); writer.write(JSONObject.quote(key)); writer.write(58); if (indentFactor > 0) { writer.write(32); } JSONObject.attemptWriteValue(writer, indentFactor, newIndent, entry, key); needsComma = true; } if (indentFactor > 0) { writer.write(10); } JSONObject.indent(writer, indent); } private static void attemptWriteValue(Writer writer, int indentFactor, int indent, Map.Entry entry, String key) { try { JSONObject.writeValue(writer, entry.getValue(), indentFactor, indent); } catch (Exception e) { throw new JSONException("Unable to write JSONObject value for key: " + key, e); } } public Map toMap() { HashMap results = new HashMap(); for (Map.Entry entry : this.entrySet()) { Object value = entry.getValue() == null || NULL.equals(entry.getValue()) ? null : (entry.getValue() instanceof JSONObject ? ((JSONObject)entry.getValue()).toMap() : (entry.getValue() instanceof JSONArray ? ((JSONArray)entry.getValue()).toList() : entry.getValue())); results.put(entry.getKey(), value); } return results; } private static JSONException wrongValueFormatException(String key, String valueType, Object value, Throwable cause) { if (value == null) { return new JSONException("JSONObject[" + JSONObject.quote(key) + "] is not a " + valueType + " (null).", cause); } if (value instanceof Map || value instanceof Iterable || value instanceof JSONObject) { return new JSONException("JSONObject[" + JSONObject.quote(key) + "] is not a " + valueType + " (" + value.getClass() + ").", cause); } return new JSONException("JSONObject[" + JSONObject.quote(key) + "] is not a " + valueType + " (" + value.getClass() + " : " + value + ").", cause); } private static JSONException recursivelyDefinedObjectException(String key) { return new JSONException("JavaBean object contains recursively defined member variable of key " + JSONObject.quote(key)); } private Class getRawType(Type type) { if (type instanceof Class) { return (Class)type; } if (type instanceof ParameterizedType) { return (Class)((ParameterizedType)type).getRawType(); } if (type instanceof GenericArrayType) { return Object[].class; } return Object.class; } private Type getElementType(Type type) { if (type instanceof ParameterizedType) { Type[] args = ((ParameterizedType)type).getActualTypeArguments(); return args.length > 0 ? args[0] : Object.class; } return Object.class; } private Type[] getMapTypes(Type type) { Type[] args; if (type instanceof ParameterizedType && (args = ((ParameterizedType)type).getActualTypeArguments()).length == 2) { return args; } return new Type[]{Object.class, Object.class}; } public static T fromJson(String jsonString, Class clazz) { JSONObject jsonObject = new JSONObject(jsonString); return jsonObject.fromJson(clazz); } public T fromJson(Class clazz) { try { T obj = clazz.getDeclaredConstructor(new Class[0]).newInstance(new Object[0]); for (Field field : clazz.getDeclaredFields()) { field.setAccessible(true); String fieldName = field.getName(); if (!this.has(fieldName)) continue; Object value = this.get(fieldName); Type fieldType = field.getGenericType(); Object convertedValue = this.convertValue(value, fieldType); field.set(obj, convertedValue); } return obj; } catch (NoSuchMethodException e) { throw new JSONException("No no-arg constructor for class: " + clazz.getName(), e); } catch (Exception e) { throw new JSONException("Failed to instantiate or set field for class: " + clazz.getName(), e); } } private Object convertValue(Object value, Type targetType) throws JSONException { if (value == null) { return null; } Class rawType = this.getRawType(targetType); if (rawType.isAssignableFrom(value.getClass())) { return value; } if (rawType == Integer.TYPE || rawType == Integer.class) { return ((Number)value).intValue(); } if (rawType == Double.TYPE || rawType == Double.class) { return ((Number)value).doubleValue(); } if (rawType == Float.TYPE || rawType == Float.class) { return Float.valueOf(((Number)value).floatValue()); } if (rawType == Long.TYPE || rawType == Long.class) { return ((Number)value).longValue(); } if (rawType == Boolean.TYPE || rawType == Boolean.class) { return value; } if (rawType == String.class) { return value; } if (rawType == BigDecimal.class) { return new BigDecimal((String)value); } if (rawType == BigInteger.class) { return new BigInteger((String)value); } if (rawType.isEnum() && value instanceof String) { return this.stringToEnum(rawType, (String)value); } if (Collection.class.isAssignableFrom(rawType)) { if (value instanceof JSONArray) { Type elementType = this.getElementType(targetType); return this.fromJsonArray((JSONArray)value, rawType, elementType); } } else { if (Map.class.isAssignableFrom(rawType) && value instanceof JSONObject) { Type[] mapTypes = this.getMapTypes(targetType); Type keyType = mapTypes[0]; Type valueType = mapTypes[1]; return this.convertToMap((JSONObject)value, keyType, valueType, rawType); } if (!rawType.isPrimitive() && !rawType.isEnum() && value instanceof JSONObject) { return ((JSONObject)value).fromJson(rawType); } } return value.toString(); } private Map convertToMap(JSONObject jsonMap, Type keyType, Type valueType, Class mapType) throws JSONException { try { HashMap createdMap = new HashMap(); Iterator iterator = jsonMap.keySet().iterator(); while (iterator.hasNext()) { String keyObj; String keyStr = keyObj = iterator.next(); Object mapValue = jsonMap.get(keyStr); Object convertedKey = this.convertValue(keyStr, keyType); Object convertedValue = this.convertValue(mapValue, valueType); createdMap.put(convertedKey, convertedValue); } return createdMap; } catch (Exception e) { throw new JSONException("Failed to convert JSONObject to Map: " + mapType.getName(), e); } } private E stringToEnum(Class enumClass, String value) throws JSONException { try { Class enumType = enumClass; Method valueOfMethod = enumType.getMethod("valueOf", String.class); return (E)valueOfMethod.invoke(null, value); } catch (Exception e) { throw new JSONException("Failed to convert string to enum: " + value + " for " + enumClass.getName(), e); } } private Collection fromJsonArray(JSONArray jsonArray, Class collectionType, Type elementType) throws JSONException { try { Collection collection = this.getCollection(collectionType); for (int i = 0; i < jsonArray.length(); ++i) { Object jsonElement = jsonArray.get(i); Object convertedValue = this.convertValue(jsonElement, elementType); collection.add(convertedValue); } return collection; } catch (Exception e) { throw new JSONException("Failed to convert JSONArray to Collection: " + collectionType.getName(), e); } } private Collection getCollection(Class collectionType) throws JSONException { if (collectionType == List.class || collectionType == ArrayList.class) { return new ArrayList(); } if (collectionType == Set.class || collectionType == HashSet.class) { return new HashSet(); } throw new JSONException("Unsupported Collection type: " + collectionType.getName()); } private static final class Null { private Null() { } public boolean equals(Object object) { return object == null || object == this; } public int hashCode() { return 0; } public String toString() { return "null"; } } }