/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.felix.utils.json; import java.io.IOException; import java.io.Writer; import java.lang.reflect.Array; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; /** * Simple JSON writer to be used on top of a {@link Writer}. */ public class JSONWriter { private final Writer pw; private boolean comma; public JSONWriter(final Writer pw) { this.comma = false; this.pw = pw; } public JSONWriter object() throws IOException { if (this.comma) this.pw.write(','); this.pw.write("{"); this.comma = false; return this; } public JSONWriter endObject() throws IOException { this.pw.write('}'); this.comma = true; return this; } public JSONWriter array() throws IOException { if (this.comma) this.pw.write(','); this.pw.write("["); this.comma = false; return this; } public JSONWriter endArray() throws IOException { this.pw.write(']'); this.comma = true; return this; } public JSONWriter key(String key) throws IOException { if (this.comma) this.pw.write(','); quote(key); this.pw.write(':'); this.comma = false; return this; } public JSONWriter value(final boolean b) throws IOException { if (this.comma) this.pw.write(','); this.pw.write(b ? "true" : "false"); this.comma = true; return this; } public JSONWriter value(final double d) throws IOException { return this.value(new Double(d)); } public JSONWriter value(final int i) throws IOException { if (this.comma) this.pw.write(','); this.pw.write(String.valueOf(i)); this.comma = true; return this; } public JSONWriter value(final long l) throws IOException { if (this.comma) this.pw.write(','); this.pw.write(String.valueOf(l)); this.comma = true; return this; } public JSONWriter value(final Object value) throws IOException { if (this.comma) { this.pw.write(','); } if (value == null || value.equals(null)) { this.pw.write("null"); } else if (value instanceof Boolean ) { this.pw.write(value.toString()); } else if (value instanceof Number) { String str = value.toString(); if ( str.indexOf('.') == -1 || str.indexOf('e') > 0 || str.indexOf('E') > 0 ) { this.pw.write(str); } else { while (str.endsWith("0")) { str = str.substring(0, str.length() - 1); } if (str.endsWith(".")) { str = str.substring(0, str.length() - 1); } this.pw.write(str); } } else if ( value instanceof Map) { this.comma = false; this.object(); final Map map = (Map)value; final Iterator iter = map.entrySet().iterator(); while ( iter.hasNext() ) { Map.Entry entry = (Entry) iter.next(); this.key((String)entry.getKey()); this.value(entry.getValue()); } this.endObject(); } else if ( value.getClass().isArray() ) { this.comma = false; this.array(); for(int i=0;i<Array.getLength(value);i++) { final Object val = Array.get(value, i); value(val); } this.endArray(); } else if ( value instanceof Collection ) { this.comma = false; this.array(); final Collection col = (Collection)value; final Iterator i = col.iterator(); while ( i.hasNext()) { value(i.next()); } this.endArray(); } else { quote(value.toString()); } this.comma = true; return this; } /** * Quote the provided value and escape some characters. * @param value The value to quote * @throws IOException */ private void quote(final String value) throws IOException { pw.write('"'); final int len = value.length(); for(int i=0;i<len;i++) { final char c = value.charAt(i); switch(c){ case '"': pw.write("\\\""); break; case '\\': pw.write("\\\\"); break; case '\b': pw.write("\\b"); break; case '\f': pw.write("\\f"); break; case '\n': pw.write("\\n"); break; case '\r': pw.write("\\r"); break; case '\t': pw.write("\\t"); break; case '/': pw.write("\\/"); break; default: if ((c>='\u0000' && c<='\u001F') || (c>='\u007F' && c<='\u009F') || (c>='\u2000' && c<='\u20FF')) { final String hex=Integer.toHexString(c); pw.write("\\u"); for(int k=0;k<4-hex.length();k++){ pw.write('0'); } pw.write(hex.toUpperCase()); } else{ pw.write(c); } } } pw.write('"'); } /** * @see Writer#flush() * @throws IOException */ public void flush() throws IOException { this.pw.flush(); } }