I'd like to convert the an Intent's extras Bundle into a JSONObject so that I can pass it to/from JavaScript.
Is there a quick or best way to do this conversion? It would be alright if not all possible Bundles will work.
You can use Bundle#keySet()
to get a list of keys that a Bundle contains. You can then iterate through those keys and add each key-value pair into a JSONObject
:
JSONObject json = new JSONObject();
Set<String> keys = bundle.keySet();
for (String key : keys) {
try {
// json.put(key, bundle.get(key)); see edit below
json.put(key, JSONObject.wrap(bundle.get(key)));
} catch(JSONException e) {
//Handle exception here
}
}
Note that JSONObject#put
will require you to catch a JSONException
.
Edit:
It was pointed out that the previous code didn't handle Collection
and Map
types very well. If you're using API 19 or higher, there's a JSONObject#wrap
method that will help if that's important to you. From the docs:
Wrap an object, if necessary. If the object is null, return the NULL object. If it is an array or collection, wrap it in a JSONArray. If it is a map, wrap it in a JSONObject. If it is a standard property (Double, String, et al) then it is already wrapped. Otherwise, if it comes from one of the java packages, turn it into a string. And if it doesn't, try to wrap it in a JSONObject. If the wrapping fails, then null is returned.
private String getJson(final Bundle bundle) {
if (bundle == null) return null;
JSONObject jsonObject = new JSONObject();
for (String key : bundle.keySet()) {
Object obj = bundle.get(key);
try {
jsonObject.put(key, wrap(bundle.get(key)));
} catch (JSONException e) {
e.printStackTrace();
}
}
return jsonObject.toString();
}
public static Object wrap(Object o) {
if (o == null) {
return JSONObject.NULL;
}
if (o instanceof JSONArray || o instanceof JSONObject) {
return o;
}
if (o.equals(JSONObject.NULL)) {
return o;
}
try {
if (o instanceof Collection) {
return new JSONArray((Collection) o);
} else if (o.getClass().isArray()) {
return toJSONArray(o);
}
if (o instanceof Map) {
return new JSONObject((Map) o);
}
if (o instanceof Boolean ||
o instanceof Byte ||
o instanceof Character ||
o instanceof Double ||
o instanceof Float ||
o instanceof Integer ||
o instanceof Long ||
o instanceof Short ||
o instanceof String) {
return o;
}
if (o.getClass().getPackage().getName().startsWith("java.")) {
return o.toString();
}
} catch (Exception ignored) {
}
return null;
}
public static JSONArray toJSONArray(Object array) throws JSONException {
JSONArray result = new JSONArray();
if (!array.getClass().isArray()) {
throw new JSONException("Not a primitive array: " + array.getClass());
}
final int length = Array.getLength(array);
for (int i = 0; i < length; ++i) {
result.put(wrap(Array.get(array, i)));
}
return result;
}
Here is a Gson type adapter factory that converts a Bundle to JSON.
https://github.com/google-gson/typeadapters/blob/master/android/src/main/java/BundleTypeAdapterFactory.java
If the bundle has nested bundles then JSONObject.wrap(bundle.get(key))
will return null
. So I managed to get it to work for my use case with this recursive function. Haven't tested more advanced use cases though.
JSONObject json = convertBundleToJson(bundle);
public JSONObject convertBundleToJson(Bundle bundle) {
JSONObject json = new JSONObject();
Set<String> keys = bundle.keySet();
for (String key : keys) {
try {
if (bundle.get(key) != null && bundle.get(key).getClass().getName().equals("android.os.Bundle")) {
Bundle nestedBundle = (Bundle) bundle.get(key);
json.put(key, convertToJson(nestedBundle));
} else {
json.put(key, JSONObject.wrap(bundle.get(key)));
}
} catch(JSONException e) {
System.out.println(e.toString());
}
}
return json;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With