    001/* ============
    002 * Orson Charts
    003 * ============
    004 *
    005 * (C)opyright 2013, 2014, by Object Refinery Limited.
    006 *
    007 * http://www.object-refinery.com/orsoncharts/index.html
    008 *
    009 * JSON.simple
    010 * -----------
    011 * The code in this file originates from the JSON.simple project by
    012 * FangYidong<fangyidong@yahoo.com.cn>:
    013 *
    014 *     https://code.google.com/p/json-simple/
    015 *
    016 * which is licensed under the Apache Software License version 2.0.
    017 *
    018 * It has been modified locally and repackaged under
    019 * com.orsoncharts.util.json.* to avoid conflicts with any other version that
    020 * may be present on the classpath.
    021 *
    022 */
    023
    024package com.orsoncharts.util.json;
    025
    026import java.io.IOException;
    027import java.io.Writer;
    028import java.util.HashMap;
    029import java.util.Iterator;
    030import java.util.Map;
    031
    032/**
    033 * A JSON object. Key value pairs are unordered.
    034 */
    035public class JSONObject extends HashMap implements Map, JSONAware,
    036        JSONStreamAware {
    037
    038    private static final long serialVersionUID = -503443796854799292L;
    039
    040    /**
    041     * Encode a map into JSON text and write it to out.
    042     * If this map is also a {@link JSONAware} or {@link JSONStreamAware},
    043     * {@code JSONAware} or {@code JSONStreamAware} specific
    044     * behaviours will be ignored at this top level.
    045     *
    046     * @see com.orsoncharts.util.json.JSONValue#writeJSONString(Object, Writer)
    047     *
    048     * @param map  the map to write ({@code null} permitted).
    049     * @param out  the output writer ({@code null} not permitted).
    050     *
    051     * @throws IOException if there is an I/O problem.
    052     */
    053    public static void writeJSONString(Map map, Writer out) throws IOException {
    054        if (map == null) {
    055            out.write("null");
    056            return;
    057        }
    058        boolean first = true;
    059        Iterator iter = map.entrySet().iterator();
    060        out.write('{');
    061        while (iter.hasNext()) {
    062            if (first) {
    063                first = false;
    064            }
    065            else {
    066                out.write(',');
    067            }
    068            Map.Entry entry = (Map.Entry) iter.next();
    069            out.write('\"');
    070            out.write(JSONValue.escape(String.valueOf(entry.getKey())));
    071            out.write('\"');
    072            out.write(':');
    073            JSONValue.writeJSONString(entry.getValue(), out);
    074        }
    075        out.write('}');
    076    }
    077
    078    /**
    079     * Writes a JSON string representing this object instance to the specified
    080     * output writer.
    081     *
    082     * @param out  the output writer ({@code null} not permitted).
    083     *
    084     * @throws IOException if there is an I/O problem.
    085     */
    086    @Override
    087    public void writeJSONString(Writer out) throws IOException {
    088        writeJSONString(this, out);
    089    }
    090
    091    /**
    092     * Convert a map to JSON text. The result is a JSON object.
    093     * If this map is also a {@link JSONAware}, {@code JSONAware} specific
    094     * behaviours will be omitted at this top level.
    095     *
    096     * @see com.orsoncharts.util.json.JSONValue#toJSONString(Object)
    097     *
    098     * @param map  the map ({@code null} permitted).
    099     *
    100     * @return JSON text, or "null" if map is null.
    101     */
    102    public static String toJSONString(Map map){
    103        if (map == null) {
    104            return "null";
    105        }
    106
    107        StringBuffer sb = new StringBuffer();
    108        boolean first = true;
    109        Iterator iter = map.entrySet().iterator();
    110
    111        sb.append('{');
    112        while (iter.hasNext()) {
    113            if (first) {
    114                first = false;
    115            }
    116            else {
    117                sb.append(',');
    118            }
    119
    120            Map.Entry entry = (Map.Entry) iter.next();
    121            toJSONString(String.valueOf(entry.getKey()), entry.getValue(), sb);
    122        }
    123        sb.append('}');
    124        return sb.toString();
    125    }
    126
    127    /**
    128     * Returns a JSON string representing this object.
    129     *
    130     * @return A JSON string.
    131     */
    132    @Override
    133    public String toJSONString(){
    134        return toJSONString(this);
    135    }
    136
    137    /**
    138     * Writes a key and value to a JSON string.
    139     *
    140     * @param key  the key ({@code null} permitted).
    141     * @param value  the value ({@code null} permitted).
    142     * @param sb  a string buffer ({@code null} not permitted).
    143     *
    144     * @return A JSON string fragment representing the key and value.
    145     */
    146    private static String toJSONString(String key, Object value,
    147            StringBuffer sb) {
    148        sb.append('\"');
    149        if (key == null) {
    150            sb.append("null");
    151        }
    152        else {
    153            JSONValue.escape(key, sb);
    154        }
    155        sb.append('\"').append(':');
    156
    157        sb.append(JSONValue.toJSONString(value));
    158
    159        return sb.toString();
    160    }
    161
    162    /**
    163     * Returns a string representation of this object.
    164     *
    165     * @return A string.
    166     */
    167    @Override
    168    public String toString(){
    169        return toJSONString();
    170    }
    171
    172    /**
    173     * Returns a JSON string fragment containing the key and value.
    174     *
    175     * @param key  the key ({@code null} permitted).
    176     * @param value  the value ({@code null} permitted).
    177     *
    178     * @return A JSON string fragment.
    179     */
    180    public static String toString(String key, Object value){
    181        StringBuffer sb = new StringBuffer();
    182        toJSONString(key, value, sb);
    183        return sb.toString();
    184    }
    185}