/* * Copyright 2017 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.firebase.database.util; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONStringer; import org.json.JSONTokener; /** * Helper class to convert from/to JSON strings. TODO: This class should ideally not live in * firebase-database-connection, but it's required by both firebase-database and * firebase-database-connection, so leave it here for now. */ public class JsonMapper { public static String serializeJson(Map<String, Object> object) throws IOException { return serializeJsonValue(object); } @SuppressWarnings("unchecked") public static String serializeJsonValue(Object object) throws IOException { if (object == null) { return "null"; } else if (object instanceof String) { return JSONObject.quote((String) object); } else if (object instanceof Number) { try { return JSONObject.numberToString((Number) object); } catch (JSONException e) { throw new IOException("Could not serialize number", e); } } else if (object instanceof Boolean) { return ((Boolean) object) ? "true" : "false"; } else { try { JSONStringer stringer = new JSONStringer(); serializeJsonValue(object, stringer); return stringer.toString(); } catch (JSONException e) { throw new IOException("Failed to serialize JSON", e); } } } private static void serializeJsonValue(Object object, JSONStringer stringer) throws IOException, JSONException { if (object instanceof Map) { stringer.object(); @SuppressWarnings("unchecked") Map<String, Object> map = (Map<String, Object>) object; for (Map.Entry<String, Object> entry : map.entrySet()) { stringer.key(entry.getKey()); serializeJsonValue(entry.getValue(), stringer); } stringer.endObject(); } else if (object instanceof Collection) { Collection<?> collection = (Collection<?>) object; stringer.array(); for (Object entry : collection) { serializeJsonValue(entry, stringer); } stringer.endArray(); } else { stringer.value(object); } } public static Map<String, Object> parseJson(String json) throws IOException { try { return unwrapJsonObject(new JSONObject(json)); } catch (JSONException e) { throw new IOException(e); } } public static Object parseJsonValue(String json) throws IOException { try { return unwrapJson(new JSONTokener(json).nextValue()); } catch (JSONException e) { throw new IOException(e); } } @SuppressWarnings("unchecked") private static Map<String, Object> unwrapJsonObject(JSONObject jsonObject) throws JSONException { Map<String, Object> map = new HashMap<>(jsonObject.length()); Iterator<String> keys = jsonObject.keys(); while (keys.hasNext()) { String key = keys.next(); map.put(key, unwrapJson(jsonObject.get(key))); } return map; } private static List<Object> unwrapJsonArray(JSONArray jsonArray) throws JSONException { List<Object> list = new ArrayList<>(jsonArray.length()); for (int i = 0; i < jsonArray.length(); i++) { list.add(unwrapJson(jsonArray.get(i))); } return list; } private static Object unwrapJson(Object o) throws JSONException { if (o instanceof JSONObject) { return unwrapJsonObject((JSONObject) o); } else if (o instanceof JSONArray) { return unwrapJsonArray((JSONArray) o); } else if (o.equals(JSONObject.NULL)) { return null; } else { return o; } } }