001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2020, by Object Refinery Limited and Contributors.
006 *
007 * Project Info:  http://www.jfree.org/jfreechart/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 * org.jfree.data.json.impl.* to avoid conflicts with any other version that
020 * may be present on the classpath.
021 * 
022 */
023
024package org.jfree.data.json.impl;
025
026
027import java.io.IOException;
028import java.io.Writer;
029import java.util.HashMap;
030import java.util.Iterator;
031import java.util.Map;
032
033/**
034 * A JSON object. Key value pairs are unordered.
035 * <br><br>
036 * This class is for internal use by JFreeChart, it is not 
037 * part of the supported API and you should not call it directly.  If you need
038 * JSON support in your project you should include JSON.simple 
039 * (https://code.google.com/p/json-simple/) or some other JSON library directly
040 * in your project.
041 */
042public class JSONObject extends HashMap implements Map, JSONAware, 
043        JSONStreamAware {
044    
045    private static final long serialVersionUID = -503443796854799292L;
046
047    /**
048     * Encode a map into JSON text and write it to out.
049     * If this map is also a {@link JSONAware} or {@link JSONStreamAware}, 
050     * {@code JSONAware} or {@code JSONStreamAware} specific 
051     * behaviours will be ignored at this top level.
052     * 
053     * @see org.jfree.data.json.impl.JSONValue#writeJSONString(Object, Writer)
054     * 
055     * @param map  the map to write ({@code null} permitted).
056     * @param out  the output writer ({@code null} not permitted).
057     * 
058     * @throws IOException if there is an I/O problem.
059     */
060    public static void writeJSONString(Map map, Writer out) throws IOException {
061        if (map == null) {
062            out.write("null");
063            return;
064        }
065        boolean first = true;
066        Iterator iter = map.entrySet().iterator();
067        out.write('{');
068        while (iter.hasNext()) {
069            if (first) {
070                first = false;
071            }
072            else {
073                out.write(',');
074            }
075            Map.Entry entry = (Map.Entry) iter.next();
076            out.write('\"');
077            out.write(JSONValue.escape(String.valueOf(entry.getKey())));
078            out.write('\"');
079            out.write(':');
080            JSONValue.writeJSONString(entry.getValue(), out);
081        }
082        out.write('}');
083    }
084
085    /**
086     * Writes a JSON string representing this object instance to the specified
087     * output writer.
088     * 
089     * @param out  the output writer ({@code null} not permitted).
090     * 
091     * @throws IOException if there is an I/O problem.
092     */
093    @Override
094    public void writeJSONString(Writer out) throws IOException {
095        writeJSONString(this, out);
096    }
097    
098    /**
099     * Convert a map to JSON text. The result is a JSON object. 
100     * If this map is also a {@link JSONAware}, {@code JSONAware} specific 
101     * behaviours will be omitted at this top level.
102     * 
103     * @see org.jfree.data.json.impl.JSONValue#toJSONString(Object)
104     * 
105     * @param map  the map ({@code null} permitted).
106     * 
107     * @return JSON text, or "null" if map is null.
108     */
109    public static String toJSONString(Map map){
110        if (map == null) {
111            return "null";
112        }
113        
114        StringBuffer sb = new StringBuffer();
115        boolean first = true;
116        Iterator iter = map.entrySet().iterator();
117        
118        sb.append('{');
119        while (iter.hasNext()) {
120            if (first) {
121                first = false;
122            }
123            else {
124                sb.append(',');
125            }
126            
127            Map.Entry entry = (Map.Entry) iter.next();
128            toJSONString(String.valueOf(entry.getKey()), entry.getValue(), sb);
129        }
130        sb.append('}');
131        return sb.toString();
132    }
133    
134    /**
135     * Returns a JSON string representing this object.
136     * 
137     * @return A JSON string. 
138     */
139    @Override
140    public String toJSONString(){
141        return toJSONString(this);
142    }
143    
144    /**
145     * Writes a key and value to a JSON string.
146     * 
147     * @param key  the key ({@code null} permitted).
148     * @param value  the value ({@code null} permitted).
149     * @param sb  a string buffer ({@code null} not permitted).
150     * 
151     * @return A JSON string fragment representing the key and value. 
152     */
153    private static String toJSONString(String key, Object value, 
154            StringBuffer sb) {
155        sb.append('\"');
156        if (key == null) {
157            sb.append("null");
158        }
159        else {
160            JSONValue.escape(key, sb);
161        }
162        sb.append('\"').append(':');
163        
164        sb.append(JSONValue.toJSONString(value));
165        
166        return sb.toString();
167    }
168    
169    /**
170     * Returns a string representation of this object.
171     * 
172     * @return A string. 
173     */
174    @Override
175    public String toString(){
176        return toJSONString();
177    }
178
179    /**
180     * Returns a JSON string fragment containing the key and value.
181     * 
182     * @param key  the key ({@code null} permitted).
183     * @param value  the value ({@code null} permitted).
184     * 
185     * @return A JSON string fragment. 
186     */
187    public static String toString(String key, Object value){
188        StringBuffer sb = new StringBuffer();
189        toJSONString(key, value, sb);
190        return sb.toString();
191    }
192}
193