Package com.github.jsonj.tools

Source Code of com.github.jsonj.tools.JsonSerializer

/**
* Copyright (c) 2011, Jilles van Gurp
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.github.jsonj.tools;

import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map.Entry;

import org.apache.commons.lang.StringEscapeUtils;

import com.github.jsonj.JsonElement;
import com.github.jsonj.JsonType;

/**
* Utility class to serialize Json.
*/
public class JsonSerializer {
    public static final Charset UTF8=Charset.forName("utf-8");
    public static final String ESCAPED_CARRIAGE_RETURN = "\\r";
    public static final String ESCAPED_TAB = "\\t";
    public static final String ESCAPED_BACKSLASH = "\\\\";
    public static final String ESCAPED_NEWLINE = "\\n";
    public static final String ESCAPED_QUOTE = "\\\"";
    public static final String OPEN_BRACKET="[";
    public static final String CLOSE_BRACKET="]";
    public static final String OPEN_BRACE="{";
    public static final String CLOSE_BRACE="}";
    public static final String COLON=":";
    public static final String QUOTE="\"";
    public static final String COMMA=",";

    private JsonSerializer() {
        // utility class, don't instantiate
    }

    /**
     * @param json a {@link JsonElement}
     * @return string representation of the json
     */
    public static String serialize(final JsonElement json) {
        return serialize(json, false);
    }

    /**
     * @param json a {@link JsonElement}
     * @param out an {@link OutputStream}
     */
    public static void serialize(final JsonElement json, OutputStream out) {
        try {
            json.serialize(out);
        } catch (IOException e) {
            throw new IllegalStateException("cannot serialize json to output stream", e);
        }
    }

    public static void serialize(final JsonElement json, Writer out) {
        try {
            json.serialize(out);
        } catch (IOException e) {
            throw new IllegalStateException("cannot serialize json to output stream", e);
        }
    }

    /**
     * @param json a {@link JsonElement}
     * @param pretty if true, a properly indented version of the json is returned
     * @return string representation of the json
     */
    public static String serialize(final JsonElement json, final boolean pretty) {
        StringWriter sw = new StringWriter();
        if(pretty) {
            try {
                serialize(sw,json,pretty);
            } catch (IOException e) {
                throw new IllegalStateException("cannot serialize json to a string", e);
            } finally {
                try {
                    sw.close();
                } catch (IOException e) {
                    throw new IllegalStateException("cannot serialize json to a string", e);
                }
            }
            return sw.getBuffer().toString();
        } else {
            try {
                json.serialize(sw);
                return sw.getBuffer().toString();
            } catch (IOException e) {
                throw new IllegalStateException("cannot serialize json to a string", e);
            }
        }
    }

    /**
     * Writes the object out as json.
     * @param out output writer
     * @param json a {@link JsonElement}
     * @param pretty if true, a properly indented version of the json is written
     * @throws IOException if there is a problem writing to the writer
     */
    public static void serialize(final Writer out, final JsonElement json, final boolean pretty) throws IOException {
        BufferedWriter bw = new BufferedWriter(out);
        serialize(bw, json, pretty, 0);
        if(pretty) {
            out.write('\n');
        }
        bw.flush();
    }

    /**
     * Writes the object out as json.
     * @param out output writer
     * @param json a {@link JsonElement}
     * @param pretty if true, a properly indented version of the json is written
     * @throws IOException if there is a problem writing to the stream
     */
    public static void serialize(final OutputStream out, final JsonElement json, final boolean pretty) throws IOException {
        BufferedOutputStream bufferedOut = new BufferedOutputStream(out);
        OutputStreamWriter w = new OutputStreamWriter(bufferedOut, UTF8);
        if(pretty) {
            serialize(w, json, pretty);
        } else {
            json.serialize(w);
            bufferedOut.flush();
        }
    }

    private static void serialize(final BufferedWriter bw, final JsonElement json, final boolean pretty, final int indent) throws IOException {
        if(json==null) {
            return;
        }
        JsonType type = json.type();
        switch (type) {
        case object:
            bw.write('{');
            newline(bw, indent+1, pretty);
            Iterator<Entry<String, JsonElement>> iterator = json.asObject().entrySet().iterator();
            while (iterator.hasNext()) {
                Entry<String, JsonElement> entry = iterator.next();
                String key = entry.getKey();
                JsonElement value = entry.getValue();
                if(value != null) {
                    bw.write('"');
                    bw.write(jsonEscape(key));
                    bw.write("\":");
                    serialize(bw,value,pretty,indent+1);
                    if(iterator.hasNext()) {
                        bw.write(',');
                        newline(bw, indent+1, pretty);
                    }
                }
            }
            newline(bw, indent, pretty);
            bw.write('}');
            break;
        case array:
            bw.write('[');
            newline(bw, indent+1, pretty);
            Iterator<JsonElement> arrayIterator = json.asArray().iterator();
            while (arrayIterator.hasNext()) {
                JsonElement value = arrayIterator.next();
                boolean nestedPretty=false;
                if(value.isObject()) {
                    nestedPretty=true;
                }
                serialize(bw,value,nestedPretty,indent+1);
                if(arrayIterator.hasNext()) {
                    bw.write(',');
                    newline(bw, indent+1, nestedPretty);
                }
            }
            newline(bw, indent, pretty);
            bw.write(']');
            break;
        case string:
            bw.write(json.toString());
            break;
        case bool:
            bw.write(json.toString());
            break;
        case number:
            bw.write(json.toString());
            break;
        case nullValue:
            bw.write(json.toString());
            break;

        default:
            throw new IllegalArgumentException("unhandled type " + type);
        }
    }

    /**
     * The xml specification defines these character hex codes as allowed: #x9 | #xA | #xD | [#x20-#xD7FF] |
     * [#xE000-#xFFFD] | [#x10000-#x10FFFF] Characters outside this range will cause parsers to reject the xml as not
     * well formed. Probably should not allow these in Json either.
     *
     * @param c
     *        a character
     * @return true if character is allowed in an XML document
     */
    public static boolean isAllowedInXml(final int c) {
        boolean ok = false;
        if (c >= 0x10000 && c <= 0x10FFFF) {
            ok = true;
        } else if (c >= 0xE000 && c <= 0xFFFD) {
            ok = true;
        } else if (c >= 0x20 && c <= 0xD7FF) {
            ok = true;
        } else if (c == 0x9 || c == 0xA || c == 0xD) {
            ok = true;
        }
        return ok;
    }

    /**
     * This method escapes strings so that parsers don't break when encountering certain characters. Note, this method
     * is designed to be robust against corrupted input and will simply silently drop illegal characters rather than trying
     * to escape them. E.g. escape control characters other than the common ones are simply dropped from the input. Unlike
     * {@link StringEscapeUtils}, this method does not convert non ascii characters to their unicode escaped notation. Since
     * {@link JsonSerializer} always uses UTF-8 this is not required.
     * @param raw any string
     * @return the json escaped string
     */
    public static String jsonEscape(String raw) {
        // can't use StringEscapeUtils here because it escapes all non ascii characters and doesn't unescape them.
        // this is unacceptable for most utf8 content where in fact you only want to escape if you really have to

        StringBuilder buf = new StringBuilder(raw.length());
        for (char c : raw.toCharArray()) {
            // escape control characters
            if (c < 32) {
                switch (c) {
                case '\b':
                    buf.append('\\');
                    buf.append('b');
                    break;
                case '\n':
                    buf.append('\\');
                    buf.append('n');
                    break;
                case '\t':
                    buf.append('\\');
                    buf.append('t');
                    break;
                case '\f':
                    buf.append('\\');
                    buf.append('f');
                    break;
                case '\r':
                    buf.append('\\');
                    buf.append('r');
                    break;
                default:
                    // note, these characters are not unescaped.
                    if (c > 0xf) {
                        buf.append("\\u00" + hex(c));
                    } else {
                        buf.append("\\u000" + hex(c));
                    }
                    break;
                }
            } else if (isAllowedInXml(c)) {
                // note, this silently drops characters that would not be allowed in XML anyway.
                switch (c) {
                case '"':
                    buf.append('\\');
                    buf.append('"');
                    break;
                case '\\':
                    buf.append('\\');
                    buf.append('\\');
                    break;
                default:
                    buf.append(c);
                    break;
                }
            }
        }
        return buf.toString();
    }

    private static String hex(char ch) {
        return Integer.toHexString(ch).toUpperCase(Locale.ENGLISH);
    }

    /**
     * @param escaped a json string that may contain escaped characters
     * @return the unescaped String
     */
    public static String jsonUnescape(String escaped) {
        StringBuilder buf=new StringBuilder(escaped.length());
        char[] chars = escaped.toCharArray();
        if(chars.length >= 2) {
            int i=1;
            while(i<chars.length) {
                if(chars[i-1] == '\\') {
                    if(chars[i]=='t') {
                        buf.append('\t');
                        i+=2;
                    } else if(chars[i]=='n') {
                        buf.append('\n');
                        i+=2;
                    } else if(chars[i]=='r') {
                        buf.append('\r');
                        i+=2;
                    } else if(chars[i] == '"') {
                        buf.append('"');
                        i+=2;
                    } else if(chars[i] == '\\') {
                        buf.append('\\');
                        i+=2;
                    } else {
                        buf.append(chars[i-1]);
                        buf.append(chars[i]);
                        i+=2;
                    }
                } else {
                    buf.append(chars[i-1]);
                    i++;
                }
            }
            if(i==chars.length) {
                // make sure to add the last character
                buf.append(chars[i-1]);
            }
            return buf.toString();
        } else {
            return escaped;
        }
    }

    private static void newline(final BufferedWriter bw, final int n, final boolean pretty) throws IOException {
        if(pretty) {
            bw.write('\n');
            for(int i=0;i<n;i++) {
                bw.write('\t');
            }
        }
    }
}
TOP

Related Classes of com.github.jsonj.tools.JsonSerializer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.