org.etlunit.util.JSonBuilderProxy Maven / Gradle / Ivy
package org.etlunit.util;
/** This class is based on the JSONBuilder from json-lib. I copied it to get rid of the dependency on a writer **/
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed 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.
*/
import net.sf.json.util.JSONUtils;
import java.util.Iterator;
import java.util.List;
/**
* JSONBuilder provides a quick and convenient way of producing JSON text. The
* texts produced strictly conform to JSON syntax rules. No whitespace is added,
* so the results are ready for transmission or storage. Each instance of
* JSONWriter can produce one JSON text.
*
* A JSONBuilder instance provides a value
method for appending
* values to the text, and a key
method for adding keys before
* values in objects. There are array
and endArray
* methods that make and bound array values, and object
and
* endObject
methods which make and bound object values. All of
* these methods return the JSONBuilder instance, permitting a cascade style.
* For example,
*
*
* new JSONBuilder(myWriter)
* .object()
* .key("JSON")
* .value("Hello, World!")
* .endObject();
*
* which writes
*
*
* {"JSON":"Hello, World!"}
*
*
* The first method called must be array
or object
.
* There are no methods for adding commas or colons. JSONBuilder adds them for
* you. Objects and arrays can be nested up to 20 levels deep.
*
* This can sometimes be easier than using a JSONObject to build a string.
*
* @author JSON.org
* @version 1
*/
@NeedsTest
public class JSonBuilderProxy
{
private static final int MAXDEPTH = 20;
/**
* The comma flag determines if a comma should be output before the next
* value.
*/
private boolean comma;
/**
* The current mode. Values: 'a' (array), 'd' (done), 'i' (initial), 'k'
* (key), 'o' (object).
*/
protected char mode;
/**
* The object/array stack.
*/
private char stack[];
/**
* The stack top index. A value of 0 indicates that the stack is empty.
*/
private int top;
/**
* The writer that will receive the output.
*/
protected StringBuilder builder = new StringBuilder();
/**
* Make a fresh JSONBuilder. It can be used to build one JSON text.
*/
public JSonBuilderProxy()
{
this.comma = false;
this.mode = 'i';
this.stack = new char[MAXDEPTH];
this.top = 0;
}
/**
* Append a value.
*
* @param s A string value.
* @return this
* @throws IllegalArgumentException If the value is out of sequence.
*/
private JSonBuilderProxy append(String s)
{
if (s == null)
{
throw new IllegalArgumentException("Null pointer");
}
if (this.mode == 'o' || this.mode == 'a')
{
if (this.comma && this.mode == 'a')
{
this.builder.append(',');
}
this.builder.append(s);
if (this.mode == 'o')
{
this.mode = 'k';
}
this.comma = true;
return this;
}
throw new IllegalArgumentException("Value out of sequence.");
}
/**
* Begin appending a new array. All values until the balancing
* endArray
will be appended to this array. The
* endArray
method must be called to mark the array's end.
*
* @return this
* @throws IllegalArgumentException If the nesting is too deep, or if the object is
* started in the wrong place (for example as a key or after the end
* of the outermost array or object).
*/
public JSonBuilderProxy array()
{
if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a')
{
this.push('a');
this.append("[");
this.comma = false;
return this;
}
throw new IllegalArgumentException("Misplaced array.");
}
/**
* End something.
*
* @param m Mode
* @param c Closing character
* @return this
* @throws IllegalArgumentException If unbalanced.
*/
private JSonBuilderProxy end(char m, char c)
{
if (this.mode != m)
{
throw new IllegalArgumentException(m == 'o' ? "Misplaced endObject." : "Misplaced endArray.");
}
this.pop(m);
this.builder.append(c);
this.comma = true;
return this;
}
/**
* End an array. This method most be called to balance calls to
* array
.
*
* @return this
* @throws IllegalArgumentException If incorrectly nested.
*/
public JSonBuilderProxy endArray()
{
return this.end('a', ']');
}
/**
* End an object. This method most be called to balance calls to
* object
.
*
* @return this
* @throws IllegalArgumentException If incorrectly nested.
*/
public JSonBuilderProxy endObject()
{
return this.end('k', '}');
}
/**
* Append a key. The key will be associated with the next value. In an
* object, every value must be preceded by a key.
*
* @param s A key string.
* @return this
* @throws IllegalArgumentException If the key is out of place. For example, keys do not
* belong in arrays or if the key is null.
*/
public JSonBuilderProxy key(String s)
{
if (s == null)
{
throw new IllegalArgumentException("Null key.");
}
if (this.mode == 'k')
{
if (this.comma)
{
this.builder.append(',');
}
this.builder.append(JSONUtils.quote(s));
this.builder.append(':');
this.comma = false;
this.mode = 'o';
return this;
}
throw new IllegalArgumentException("Misplaced key.");
}
/**
* Begin appending a new object. All keys and values until the balancing
* endObject
will be appended to this object. The
* endObject
method must be called to mark the object's end.
*
* @return this
* @throws IllegalArgumentException If the nesting is too deep, or if the object is
* started in the wrong place (for example as a key or after the end
* of the outermost array or object).
*/
public JSonBuilderProxy object()
{
if (this.mode == 'i')
{
this.mode = 'o';
}
if (this.mode == 'o' || this.mode == 'a')
{
this.append("{");
this.push('k');
this.comma = false;
return this;
}
throw new IllegalArgumentException("Misplaced object.");
}
/**
* Pop an array or object scope.
*
* @param c The scope to close.
* @throws IllegalArgumentException If nesting is wrong.
*/
private void pop(char c)
{
if (this.top <= 0 || this.stack[this.top - 1] != c)
{
throw new IllegalArgumentException("Nesting error.");
}
this.top -= 1;
this.mode = this.top == 0 ? 'd' : this.stack[this.top - 1];
}
/**
* Push an array or object scope.
*
* @param c The scope to open.
* @throws IllegalArgumentException If nesting is too deep.
*/
private void push(char c)
{
if (this.top >= MAXDEPTH)
{
throw new IllegalArgumentException("Nesting too deep.");
}
this.stack[this.top] = c;
this.mode = c;
this.top += 1;
}
/**
* Append either the value true
or the value
* false
.
*
* @param b A boolean.
* @return this
* @throws IllegalArgumentException
*/
public JSonBuilderProxy value(boolean b)
{
return this.append(b ? "true" : "false");
}
/**
* Append a double value.
*
* @param d A double.
* @return this
* @throws IllegalArgumentException If the number is not finite.
*/
public JSonBuilderProxy value(double d)
{
return this.value(new Double(d));
}
public JSonBuilderProxy value(long l)
{
return this.append(Long.toString(l));
}
public JSonBuilderProxy value(List array)
{
JSonBuilderProxy proxy = this.array();
Iterator it = array.iterator();
while (it.hasNext())
{
proxy = proxy.value(it.next());
}
proxy = proxy.endArray();
return proxy;
}
/**
* Append an object value.
*
* @param o The object to append. It can be null, or a Boolean, Number,
* String, JSONObject, or JSONArray, or an object with a
* toJSONString() method.
* @return this
* @throws IllegalArgumentException If the value is out of sequence.
*/
public JSonBuilderProxy value(Object o)
{
return this.append(JSONUtils.valueToString(o));
}
public String toString()
{
return builder.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy