| /* |
| * 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 when the underlying writer throws an exception. |
| */ |
| public void flush() throws IOException |
| { |
| this.pw.flush(); |
| } |
| } |