/*
JSONFactory.java
Copyright (c) 2014 NTT DOCOMO,INC.
Released under the MIT license
http://opensource.org/licenses/mit-license.php
*/
package org.deviceconnect.utils;
import android.os.Bundle;
import android.os.Parcelable;
import org.deviceconnect.message.intent.message.IntentDConnectMessage;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.List;
/**
* JSONファクトリークラス.
* JSONデータを生成する機能を提供する。
*
*
* @author NTT DOCOMO, INC.
*/
public final class JSONUtils {
/**
* ユーティリティクラスなのでprivate.
*/
private JSONUtils() {
}
/**
* BundleをJSONObjectに変換する.
*
* @param bundle 変換するBundle
* @return 変換後のJSONデータ
* @throws JSONException JSONへの変換に失敗した場合に発生
*/
public static JSONObject convertBundleToJSON(final Bundle bundle) throws JSONException {
JSONObject json = new JSONObject();
convertBundleToJSON(json, bundle);
return json;
}
/**
* BundleからJSONObjectに変換する.
* @param root JSONObjectに変換したデータを格納するオブジェクト
* @param b 変換するBundle
* @throws JSONException JSONへの変換に失敗した場合に発生
*/
public static void convertBundleToJSON(
final JSONObject root, final Bundle b) throws JSONException {
if (root == null || b == null) {
return;
}
for (String key : b.keySet()) {
Object value = b.get(key);
if (key.equals(IntentDConnectMessage.EXTRA_REQUEST_CODE)) {
// request_codeはRESTfulにはいらないので削除しておく
continue;
} else if (value instanceof Integer[] || value instanceof Long[] || value instanceof Short[]
|| value instanceof Byte[] || value instanceof Character[] || value instanceof Float[]
|| value instanceof Double[] || value instanceof Boolean[] || value instanceof String[]) {
Object[] bb = (Object[]) value;
JSONArray array = new JSONArray();
for (int i = 0; i < bb.length; i++) {
array.put(bb[i]);
}
root.put(key, array);
} else if (value instanceof Integer) {
root.put(key, ((Integer) value).intValue());
} else if (value instanceof int[]) {
int[] bb = (int[]) value;
JSONArray array = new JSONArray();
for (int i = 0; i < bb.length; i++) {
array.put(bb[i]);
}
root.put(key, array);
} else if (value instanceof Short) {
root.put(key, ((Short) value).shortValue());
} else if (value instanceof short[]) {
short[] bb = (short[]) value;
JSONArray array = new JSONArray();
for (int i = 0; i < bb.length; i++) {
array.put(bb[i]);
}
root.put(key, array);
} else if (value instanceof Character) {
root.put(key, ((Character) value).charValue());
} else if (value instanceof char[]) {
char[] bb = (char[]) value;
JSONArray array = new JSONArray();
for (int i = 0; i < bb.length; i++) {
array.put(bb[i]);
}
root.put(key, array);
} else if (value instanceof Byte) {
root.put(key, ((Byte) value).byteValue());
} else if (value instanceof byte[]) {
byte[] bb = (byte[]) value;
JSONArray array = new JSONArray();
for (int i = 0; i < bb.length; i++) {
array.put(bb[i]);
}
root.put(key, array);
} else if (value instanceof Long) {
root.put(key, ((Long) value).longValue());
} else if (value instanceof long[]) {
long[] bb = (long[]) value;
JSONArray array = new JSONArray();
for (int i = 0; i < bb.length; i++) {
array.put(bb[i]);
}
root.put(key, array);
} else if (value instanceof Float) {
root.put(key, ((Float) value).floatValue());
} else if (value instanceof float[]) {
float[] bb = (float[]) value;
JSONArray array = new JSONArray();
for (int i = 0; i < bb.length; i++) {
array.put(bb[i]);
}
root.put(key, array);
} else if (value instanceof Double) {
root.put(key, ((Double) value).doubleValue());
} else if (value instanceof double[]) {
double[] bb = (double[]) value;
JSONArray array = new JSONArray();
for (int i = 0; i < bb.length; i++) {
array.put(bb[i]);
}
root.put(key, array);
} else if (value instanceof Boolean) {
root.put(key, ((Boolean) value).booleanValue());
} else if (value instanceof boolean[]) {
boolean[] bb = (boolean[]) value;
JSONArray array = new JSONArray();
for (int i = 0; i < bb.length; i++) {
array.put(bb[i]);
}
root.put(key, array);
} else if (value instanceof String) {
root.put(key, (String) value);
} else if (value instanceof Bundle) {
JSONObject obj = new JSONObject();
convertBundleToJSON(obj, (Bundle) value);
root.put(key, obj);
} else if (value instanceof Bundle[]) {
Bundle[] bb = (Bundle[]) value;
JSONArray array = new JSONArray();
for (int i = 0; i < bb.length; i++) {
JSONObject obj = new JSONObject();
convertBundleToJSON(obj, bb[i]);
array.put(obj);
}
root.put(key, array);
} else if (value instanceof Parcelable[]) {
Parcelable[] bb = (Parcelable[]) value;
JSONArray array = new JSONArray();
for (int i = 0; i < bb.length; i++) {
JSONObject obj = new JSONObject();
if (bb[i] instanceof Bundle) {
convertBundleToJSON(obj, (Bundle) bb[i]);
}
array.put(obj);
}
root.put(key, array);
} else if (value instanceof Object[]) {
// プリミティブ型のラッパークラスの配列がObject[]として扱われる場合への対処
Object[] bb = (Object[]) value;
if (isPrimitiveWrapperArray(bb)) {
JSONArray array = new JSONArray();
for (int i = 0; i < bb.length; i++) {
array.put(bb[i]);
}
root.put(key, array);
}
} else if (value instanceof List<?>) {
List<?> bb = (List<?>) value;
JSONArray array = new JSONArray();
for (int i = 0; i < bb.size(); i++) {
Object v = bb.get(i);
if (v instanceof Bundle) {
JSONObject obj = new JSONObject();
convertBundleToJSON(obj, (Bundle) bb.get(i));
array.put(obj);
} else if (v instanceof Parcelable) {
JSONObject obj = new JSONObject();
convertBundleToJSON(obj, (Bundle) bb.get(i));
array.put(obj);
} else {
array.put(bb.get(i));
}
}
root.put(key, array);
}
}
}
/**
* 指定したObject[]がプリミティブ型のラッパークラスの配列であるかどうかをチェックする.
* <p>
* なお、配列のすべての要素の型が同一でない場合、falseを返す.
* 例えば、以下のような場合.
* </p>
* <pre>
* {new Integer(0), new Double(0.0d)} // falseを返す
* </pre>
* @param array チェックするオブジェクト配列
* @return プリミティブ型のラッパークラスの配列である場合はtrue、そうでない場合はfalse
*/
private static boolean isPrimitiveWrapperArray(final Object[] array) {
String classNameCache = null;
for (int i = 0; i < array.length; i++) {
Object obj = array[i];
if (obj != null) {
if (isPrimitiveWrapper(obj)) {
String className = obj.getClass().getName();
if (classNameCache != null) {
if (!classNameCache.equals(className)) {
return false;
}
} else {
classNameCache = className;
}
} else {
return false;
}
}
}
return true;
}
/**
* 指定したObjectがプリミティブ型のラッパークラスであるかどうかをチェックする.
*
* @param obj チェックするオブジェクト
* @return プリミティブ型のラッパークラスである場合はtrue、そうでない場合はfalse
*/
private static boolean isPrimitiveWrapper(final Object obj) {
return obj instanceof Byte || obj instanceof Short || obj instanceof Integer
|| obj instanceof Long || obj instanceof Float || obj instanceof Double
|| obj instanceof Character || obj instanceof Boolean;
}
}