Home » apache-tomcat-6.0.26-src » org.apache » tomcat » util » json » [javadoc | source]

    1   package org.apache.tomcat.util.json;
    2   
    3   import java.io.IOException;
    4   import java.io.Writer;
    5   
    6   /*
    7   Copyright (c) 2006 JSON.org
    8   
    9   Permission is hereby granted, free of charge, to any person obtaining a copy
   10   of this software and associated documentation files (the "Software"), to deal
   11   in the Software without restriction, including without limitation the rights
   12   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   13   copies of the Software, and to permit persons to whom the Software is
   14   furnished to do so, subject to the following conditions:
   15   
   16   The above copyright notice and this permission notice shall be included in all
   17   copies or substantial portions of the Software.
   18   
   19   The Software shall be used for Good, not Evil.
   20   
   21   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   22   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   23   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   24   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   25   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   26   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   27   SOFTWARE.
   28   */
   29   
   30   /**
   31    * JSONWriter provides a quick and convenient way of producing JSON text.
   32    * The texts produced strictly conform to JSON syntax rules. No whitespace is
   33    * added, so the results are ready for transmission or storage. Each instance of
   34    * JSONWriter can produce one JSON text.
   35    * <p>
   36    * A JSONWriter instance provides a <code>value</code> method for appending
   37    * values to the
   38    * text, and a <code>key</code>
   39    * method for adding keys before values in objects. There are <code>array</code>
   40    * and <code>endArray</code> methods that make and bound array values, and
   41    * <code>object</code> and <code>endObject</code> methods which make and bound
   42    * object values. All of these methods return the JSONWriter instance,
   43    * permitting a cascade style. For example, <pre>
   44    * new JSONWriter(myWriter)
   45    *     .object()
   46    *         .key("JSON")
   47    *         .value("Hello, World!")
   48    *     .endObject();</pre> which writes <pre>
   49    * {"JSON":"Hello, World!"}</pre>
   50    * <p>
   51    * The first method called must be <code>array</code> or <code>object</code>.
   52    * There are no methods for adding commas or colons. JSONWriter adds them for
   53    * you. Objects and arrays can be nested up to 20 levels deep.
   54    * <p>
   55    * This can sometimes be easier than using a JSONObject to build a string.
   56    * @author JSON.org
   57    * @version 2008-09-18
   58    */
   59   public class JSONWriter {
   60       private static final int maxdepth = 20;
   61   
   62       /**
   63        * The comma flag determines if a comma should be output before the next
   64        * value.
   65        */
   66       private boolean comma;
   67   
   68       /**
   69        * The current mode. Values:
   70        * 'a' (array),
   71        * 'd' (done),
   72        * 'i' (initial),
   73        * 'k' (key),
   74        * 'o' (object).
   75        */
   76       protected char mode;
   77   
   78       /**
   79        * The object/array stack.
   80        */
   81       private JSONObject stack[];
   82   
   83       /**
   84        * The stack top index. A value of 0 indicates that the stack is empty.
   85        */
   86       private int top;
   87   
   88       /**
   89        * The writer that will receive the output.
   90        */
   91       protected Writer writer;
   92   
   93       /**
   94        * Make a fresh JSONWriter. It can be used to build one JSON text.
   95        */
   96       public JSONWriter(Writer w) {
   97           this.comma = false;
   98           this.mode = 'i';
   99           this.stack = new JSONObject[maxdepth];
  100           this.top = 0;
  101           this.writer = w;
  102       }
  103   
  104       /**
  105        * Append a value.
  106        * @param s A string value.
  107        * @return this
  108        * @throws JSONException If the value is out of sequence.
  109        */
  110       private JSONWriter append(String s) throws JSONException {
  111           if (s == null) {
  112               throw new JSONException("Null pointer");
  113           }
  114           if (this.mode == 'o' || this.mode == 'a') {
  115               try {
  116                   if (this.comma && this.mode == 'a') {
  117                       this.writer.write(',');
  118                   }
  119                   this.writer.write(s);
  120               } catch (IOException e) {
  121                   throw new JSONException(e);
  122               }
  123               if (this.mode == 'o') {
  124                   this.mode = 'k';
  125               }
  126               this.comma = true;
  127               return this;
  128           }
  129           throw new JSONException("Value out of sequence.");
  130       }
  131   
  132       /**
  133        * Begin appending a new array. All values until the balancing
  134        * <code>endArray</code> will be appended to this array. The
  135        * <code>endArray</code> method must be called to mark the array's end.
  136        * @return this
  137        * @throws JSONException If the nesting is too deep, or if the object is
  138        * started in the wrong place (for example as a key or after the end of the
  139        * outermost array or object).
  140        */
  141       public JSONWriter array() throws JSONException {
  142           if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
  143               this.push(null);
  144               this.append("[");
  145               this.comma = false;
  146               return this;
  147           }
  148           throw new JSONException("Misplaced array.");
  149       }
  150   
  151       /**
  152        * End something.
  153        * @param m Mode
  154        * @param c Closing character
  155        * @return this
  156        * @throws JSONException If unbalanced.
  157        */
  158       private JSONWriter end(char m, char c) throws JSONException {
  159           if (this.mode != m) {
  160               throw new JSONException(m == 'o' ? "Misplaced endObject." :
  161                   "Misplaced endArray.");
  162           }
  163           this.pop(m);
  164           try {
  165               this.writer.write(c);
  166           } catch (IOException e) {
  167               throw new JSONException(e);
  168           }
  169           this.comma = true;
  170           return this;
  171       }
  172   
  173       /**
  174        * End an array. This method most be called to balance calls to
  175        * <code>array</code>.
  176        * @return this
  177        * @throws JSONException If incorrectly nested.
  178        */
  179       public JSONWriter endArray() throws JSONException {
  180           return this.end('a', ']');
  181       }
  182   
  183       /**
  184        * End an object. This method most be called to balance calls to
  185        * <code>object</code>.
  186        * @return this
  187        * @throws JSONException If incorrectly nested.
  188        */
  189       public JSONWriter endObject() throws JSONException {
  190           return this.end('k', '}');
  191       }
  192   
  193       /**
  194        * Append a key. The key will be associated with the next value. In an
  195        * object, every value must be preceded by a key.
  196        * @param s A key string.
  197        * @return this
  198        * @throws JSONException If the key is out of place. For example, keys
  199        *  do not belong in arrays or if the key is null.
  200        */
  201       public JSONWriter key(String s) throws JSONException {
  202           if (s == null) {
  203               throw new JSONException("Null key.");
  204           }
  205           if (this.mode == 'k') {
  206               try {
  207                   if (this.comma) {
  208                       this.writer.write(',');
  209                   }
  210                   stack[top - 1].putOnce(s, Boolean.TRUE);
  211                   this.writer.write(JSONObject.quote(s));
  212                   this.writer.write(':');
  213                   this.comma = false;
  214                   this.mode = 'o';
  215                   return this;
  216               } catch (IOException e) {
  217                   throw new JSONException(e);
  218               }
  219           }
  220           throw new JSONException("Misplaced key.");
  221       }
  222   
  223   
  224       /**
  225        * Begin appending a new object. All keys and values until the balancing
  226        * <code>endObject</code> will be appended to this object. The
  227        * <code>endObject</code> method must be called to mark the object's end.
  228        * @return this
  229        * @throws JSONException If the nesting is too deep, or if the object is
  230        * started in the wrong place (for example as a key or after the end of the
  231        * outermost array or object).
  232        */
  233       public JSONWriter object() throws JSONException {
  234           if (this.mode == 'i') {
  235               this.mode = 'o';
  236           }
  237           if (this.mode == 'o' || this.mode == 'a') {
  238               this.append("{");
  239               this.push(new JSONObject());
  240               this.comma = false;
  241               return this;
  242           }
  243           throw new JSONException("Misplaced object.");
  244   
  245       }
  246   
  247   
  248       /**
  249        * Pop an array or object scope.
  250        * @param c The scope to close.
  251        * @throws JSONException If nesting is wrong.
  252        */
  253       private void pop(char c) throws JSONException {
  254           if (this.top <= 0) {
  255               throw new JSONException("Nesting error.");
  256           }
  257           char m = this.stack[this.top - 1] == null ? 'a' : 'k';
  258           if (m != c) {
  259               throw new JSONException("Nesting error.");
  260           }
  261           this.top -= 1;
  262           this.mode = this.top == 0 ? 'd' : this.stack[this.top - 1] == null ? 'a' : 'k';
  263       }
  264   
  265       /**
  266        * Push an array or object scope.
  267        * @param c The scope to open.
  268        * @throws JSONException If nesting is too deep.
  269        */
  270       private void push(JSONObject jo) throws JSONException {
  271           if (this.top >= maxdepth) {
  272               throw new JSONException("Nesting too deep.");
  273           }
  274           this.stack[this.top] = jo;
  275           this.mode = jo == null ? 'a' : 'k';
  276           this.top += 1;
  277       }
  278   
  279   
  280       /**
  281        * Append either the value <code>true</code> or the value
  282        * <code>false</code>.
  283        * @param b A boolean.
  284        * @return this
  285        * @throws JSONException
  286        */
  287       public JSONWriter value(boolean b) throws JSONException {
  288           return this.append(b ? "true" : "false");
  289       }
  290   
  291       /**
  292        * Append a double value.
  293        * @param d A double.
  294        * @return this
  295        * @throws JSONException If the number is not finite.
  296        */
  297       public JSONWriter value(double d) throws JSONException {
  298           return this.value(new Double(d));
  299       }
  300   
  301       /**
  302        * Append a long value.
  303        * @param l A long.
  304        * @return this
  305        * @throws JSONException
  306        */
  307       public JSONWriter value(long l) throws JSONException {
  308           return this.append(Long.toString(l));
  309       }
  310   
  311   
  312       /**
  313        * Append an object value.
  314        * @param o The object to append. It can be null, or a Boolean, Number,
  315        *   String, JSONObject, or JSONArray, or an object with a toJSONString()
  316        *   method.
  317        * @return this
  318        * @throws JSONException If the value is out of sequence.
  319        */
  320       public JSONWriter value(Object o) throws JSONException {
  321           return this.append(JSONObject.valueToString(o));
  322       }
  323   }

Home » apache-tomcat-6.0.26-src » org.apache » tomcat » util » json » [javadoc | source]