/* * 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.wink.json4j; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.apache.wink.json4j.internal.Parser; /** * Extension of the basic JSONObject. This class allows control of the serialization order of attributes. * The order in which items are put into the instance controls the order in which they are serialized out. For example, the * last item put is the last item serialized. * <BR><BR> * JSON-able values are: null, and instances of String, Boolean, Number, JSONObject and JSONArray. * <BR><BR> * Instances of this class are not thread-safe. */ public class OrderedJSONObject extends JSONObject { private static final long serialVersionUID = -3269263069889337299L; private ArrayList order = null; /** * Create a new instance of this class. */ public OrderedJSONObject() { super(); this.order = new ArrayList(); } /** * Create a new instance of this class from the provided JSON object string. * Note: This is the same as calling new OrderedJSONObject(str, false). * @param str The String of JSON to parse * @throws JSONException Thrown when the string passed is null, or malformed JSON.. */ public OrderedJSONObject(String str) throws JSONException { super(); this.order = new ArrayList(); StringReader reader = new StringReader(str); (new Parser(reader)).parse(true, this); } /** * Create a new instance of this class from the provided JSON object string. * @param str The String of JSON to parse * @param strict Boolean flag indicating if strict mode should be used. Strict mode means comments and unquoted strings are not allowed. * @throws JSONException Thrown when the string passed is null, or malformed JSON.. */ public OrderedJSONObject(String str, boolean strict) throws JSONException { super(); this.order = new ArrayList(); StringReader reader = new StringReader(str); (new Parser(reader, strict)).parse(true, this); } /** * Create a new instance of this class from the data provided from the reader. The reader content must be a JSON object string. * Note: The reader will not be closed, that is left to the caller. * Note: This is the same as calling new OrderedJSONObject(rdr, false). * @param rdr The reader from which to read the JSON to parse * @throws JSONException Thrown when the string passed is null, or malformed JSON.. */ public OrderedJSONObject(Reader rdr) throws JSONException { super(); this.order = new ArrayList(); (new Parser(rdr)).parse(true, this); } /** * Create a new instance of this class from the data provided from the reader. The reader content must be a JSON object string. * Note: The reader will not be closed, that is left to the caller. * @param rdr The reader from which to read the JSON to parse * @param strict Boolean flag indicating if strict mode should be used. Strict mode means comments and unquoted strings are not allowed. * @throws JSONException Thrown when the string passed is null, or malformed JSON.. */ public OrderedJSONObject(Reader rdr, boolean strict) throws JSONException { super(); this.order = new ArrayList(); (new Parser(rdr, strict)).parse(true, this); } /** * Create a new instance of this class from the data provided from the input stream. The stream content must be a JSON object string. * Note: The input stream content is assumed to be UTF-8 encoded. * Note: The InputStream will not be closed, that is left to the caller. * Note: This is the same as calling new OrderedJSONObject(is, false). * @param is The InputStream from which to read the JSON to parse * @throws JSONException Thrown when the string passed is null, or malformed JSON.. */ public OrderedJSONObject (InputStream is) throws JSONException { super(); this.order = new ArrayList(); InputStreamReader isr = null; if (is != null) { try { isr = new InputStreamReader(is, "UTF-8"); } catch (Exception ex) { isr = new InputStreamReader(is); } } else { throw new JSONException("Inputstream cannot be null"); } (new Parser(isr)).parse(true, this); } /** * Create a new instance of this class from the data provided from the input stream. The stream content must be a JSON object string. * Note: The input stream content is assumed to be UTF-8 encoded. * Note: The InputStream will not be closed, that is left to the caller. * @param is The InputStream from which to read the JSON to parse * @param strict Boolean flag indicating if strict mode should be used. Strict mode means comments and unquoted strings are not allowed. * @throws JSONException Thrown when the string passed is null, or malformed JSON.. */ public OrderedJSONObject (InputStream is, boolean strict) throws JSONException { super(); this.order = new ArrayList(); InputStreamReader isr = null; if (is != null) { try { isr = new InputStreamReader(is, "UTF-8"); } catch (Exception ex) { isr = new InputStreamReader(is); } } else { throw new JSONException("Inputstream cannot be null"); } (new Parser(isr, strict)).parse(true, this); } /** * Create a new instance of this class using the contents of the provided map. * The contents of the map should be values considered JSONable. * @param map The map of key/value pairs to insert into this JSON object * @throws JSONException Thrown when contents in the map cannot be made JSONable. * @throws NullPointerException Thrown if the map is null, or a key in the map is null.. */ public OrderedJSONObject(Map map) throws JSONException { super(); this.order = new ArrayList(); Set set = map.keySet(); if (set != null) { Iterator itr = set.iterator(); if (itr != null) { while (itr.hasNext()) { Object key = itr.next(); String sKey = key.toString(); this.put(sKey, map.get(key)); } } } } /** * Method to put a JSON'able object into the instance. Note that the order of initial puts controls the order of serialization. * Meaning that the first time an item is put into the object determines is position of serialization. Subsequent puts with the same * key replace the existing entry value and leave serialization position alone. For moving the position, the object must be removed, * then re-put. * @see java.util.HashMap#put(java.lang.Object, java.lang.Object) */ public Object put(Object key, Object value) { if (null == key) throw new IllegalArgumentException("key must not be null"); if (!(key instanceof String)) throw new IllegalArgumentException("key must be a String"); if (!isValidObject(value)) { if (value != null) { throw new IllegalArgumentException("Invalid type of value. Type: [" + value.getClass().getName() + "] with value: [" + value.toString() + "]"); } else { throw new IllegalArgumentException("Invalid type of value."); } } /** * Only put it in the ordering list if it isn't already present. */ if (!this.containsKey(key)) { this.order.add(key); } return super.put(key, value); } /** * Method to remove an entry from the OrderedJSONObject instance. * @see java.util.HashMap#remove(java.lang.Object) */ public Object remove(Object key) { Object retVal = null; if (null == key) throw new IllegalArgumentException("key must not be null"); if (this.containsKey(key)) { retVal = super.remove(key); for (int i = 0; i < this.order.size(); i++) { Object obj = this.order.get(i); if (obj.equals(key)) { this.order.remove(i); break; } } } return retVal; } /** * (non-Javadoc) * @see java.util.HashMap#clear() */ public void clear() { super.clear(); this.order.clear(); } /** * Returns a shallow copy of this HashMap instance: the keys and values themselves are not cloned. */ public Object clone() { OrderedJSONObject clone = (OrderedJSONObject)super.clone(); Iterator order = clone.getOrder(); ArrayList orderList = new ArrayList(); while (order.hasNext()) { orderList.add(order.next()); clone.order = orderList; } return clone; } /** * Method to obtain the order in which the items will be serialized. * @return An iterator that represents the attribute names in the order that they will be serialized. */ public Iterator getOrder() { return this.order.iterator(); } }