package org.wordpress.android.util;
import android.util.Log;
import org.json.JSONObject;
import org.json.JSONArray;
import org.json.JSONException;
import java.util.ArrayList;
import java.util.List;
public class JSONUtil {
private static String QUERY_SEPERATOR = ".";
private static String QUERY_ARRAY_INDEX_START = "[";
private static String QUERY_ARRAY_INDEX_END = "]";
private static String QUERY_ARRAY_FIRST = "first";
private static String QUERY_ARRAY_LAST = "last";
private static final String TAG = "JSONUtil";
/**
* Given a JSONObject and a key path (e.g property.child) and a default it
* will traverse the object graph and pull out the desired property
*/
public static <U> U queryJSON(JSONObject source, String query,
U defaultObject) {
int nextSeperator = query.indexOf(QUERY_SEPERATOR);
int nextIndexStart = query.indexOf(QUERY_ARRAY_INDEX_START);
if (nextSeperator == -1 && nextIndexStart == -1) {
// last item let's get it
try {
if (!source.has(query))
return defaultObject;
Object result = source.get(query);
if (result.getClass()
.isAssignableFrom(defaultObject.getClass())) {
return (U) result;
} else {
return defaultObject;
}
} catch (JSONException e) {
Log.e(TAG, String.format("Could not complete query %s", query),
e);
return defaultObject;
} catch (ClassCastException e) {
Log.e(TAG, String.format("Could not cast object %s", query), e);
return defaultObject;
}
}
int endQuery;
if (nextSeperator == -1 || nextIndexStart == -1) {
endQuery = Math.max(nextSeperator, nextIndexStart);
} else {
endQuery = Math.min(nextSeperator, nextIndexStart);
}
String nextQuery = query.substring(endQuery);
String key = query.substring(0, endQuery);
try {
if (nextQuery.indexOf(QUERY_SEPERATOR) == 0) {
return queryJSON(source.getJSONObject(key),
nextQuery.substring(1), defaultObject);
} else if (nextQuery.indexOf(QUERY_ARRAY_INDEX_START) == 0) {
return queryJSON(source.getJSONArray(key), nextQuery,
defaultObject);
} else if (!nextQuery.equals("")) {
return defaultObject;
}
Object result = source.get(key);
if (result.getClass().isAssignableFrom(defaultObject.getClass())) {
return (U) result;
} else {
return defaultObject;
}
} catch (java.lang.ClassCastException e) {
Log.e(TAG, String.format("Could not cast object at %s", query), e);
return defaultObject;
} catch (JSONException e) {
Log.e(TAG, String.format("Could not complete query %s", query), e);
return defaultObject;
}
}
/**
* Given a JSONArray and a query (e.g. [0].property) it will traverse the
* array and pull out the requested property.
*
* Acceptable indexes include negative numbers to reference items from the
* end of the list as well as "last" and "first" as more explicit references
* to "0" and "-1"
*/
public static <U> U queryJSON(JSONArray source, String query,
U defaultObject) {
// query must start with [ have an index and then have ]
int indexStart = query.indexOf(QUERY_ARRAY_INDEX_START);
int indexEnd = query.indexOf(QUERY_ARRAY_INDEX_END);
if (indexStart == -1 || indexEnd == -1 || indexStart > indexEnd) {
return defaultObject;
}
// get "index" from "[index]"
String indexStr = query.substring(indexStart + 1, indexEnd);
int index;
if (indexStr.equals(QUERY_ARRAY_FIRST)) {
index = 0;
} else if (indexStr.equals(QUERY_ARRAY_LAST)) {
index = -1;
} else {
index = Integer.parseInt(indexStr);
}
if (index < 0) {
index = source.length() + index;
}
// copy remaining query
String remainingQuery = query.substring(indexEnd + 1);
try {
if (remainingQuery.indexOf(QUERY_ARRAY_INDEX_START) == 0) {
return queryJSON(source.getJSONArray(index), remainingQuery,
defaultObject);
} else if (remainingQuery.indexOf(QUERY_SEPERATOR) == 0) {
return queryJSON(source.getJSONObject(index),
remainingQuery.substring(1), defaultObject);
} else if (!remainingQuery.equals("")) {
// TODO throw an exception since the query isn't valid?
Log.d(TAG, String.format("Incorrect query for next object %s",
remainingQuery));
return defaultObject;
}
Object result = source.get(index);
if (result.getClass().isAssignableFrom(defaultObject.getClass())) {
return (U) result;
} else {
return defaultObject;
}
} catch (java.lang.ClassCastException e) {
Log.e(TAG, String.format("Could not cast object at %s", query), e);
return defaultObject;
} catch (JSONException e) {
Log.e(TAG, String.format("Could not complete query %s", query), e);
return defaultObject;
}
}
/**
* Convert a JSONArray (expected to contain strings) in a string list
*/
public static ArrayList<String> fromJSONArrayToStringList(
JSONArray jsonArray) {
ArrayList<String> stringList = new ArrayList<String>();
for (int i = 0; i < jsonArray.length(); i++) {
try {
stringList.add(jsonArray.getString(i));
} catch (JSONException e) {
e.printStackTrace();
}
}
return stringList;
}
/**
* Convert a string list in a JSONArray
*/
public static JSONArray fromStringListToJSONArray(
ArrayList<String> stringList) {
JSONArray jsonArray = new JSONArray();
if (stringList != null)
for (int i = 0; i < stringList.size(); i++) {
jsonArray.put(stringList.get(i));
}
return jsonArray;
}
}