
org.bitbucket.cowwoc.tojsonstring.ToJsonString Maven / Gradle / Ivy
Show all versions of ToJsonString Show documentation
package org.bitbucket.cowwoc.tojsonstring;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.Map;
import java.util.Map.Entry;
import org.bitbucket.cowwoc.preconditions.Preconditions;
/**
* Generates a JSON representation of an Object.
*
* @author Gili Tzabari
*/
public final class ToJsonString
{
/**
* Styles for opening braces.
*/
@SuppressWarnings("PublicInnerClass")
public static enum BraceStyle
{
/**
* Opening brace should go on the same line as the key.
*/
SAME_LINE,
/**
* Opening brace should go on the line after the key.
*/
NEW_LINE;
}
private final StringBuilder builder;
private BraceStyle braceStyle = BraceStyle.NEW_LINE;
private int indentSize = 2;
private final Map map = Maps.newLinkedHashMap();
/**
* Creates a new ToJsonString.
*
* @param className the name of the class we are processing
* @throws NullPointerException if className or braceStyle are null
* @throws IllegalArgumentException if indentSize is negative
*/
public ToJsonString(String className)
throws NullPointerException, IllegalArgumentException
{
Preconditions.requireThat(className, "className").isNotNull();
this.builder = new StringBuilder(32).append(className);
}
/**
* Creates a new ToJsonString. Uses Reflection to associate the names of all fields with their values. This method
* does not process superclass properties.
*
* @param clazz the class whose fields to process
* @param obj the object whose values to read
* @throws NullPointerException if clazz or obj are null
* @throws IllegalArgumentException if the specified object is not an instance of the class or interface declaring the
* underlying field (or a subclass or implementor thereof)
*/
public ToJsonString(Class> clazz, Object obj)
throws NullPointerException, IllegalArgumentException
{
this(clazz.getName());
putAllFields(clazz, obj);
}
/**
* Sets the number of characters to use when indenting output.
*
* @param indentSize the number of characters to use when indenting output
* @throws IllegalArgumentException if indentSize is negative
* @return this
*/
public ToJsonString setIndentSize(int indentSize)
throws IllegalArgumentException
{
Preconditions.requireThat(indentSize, "indentSize").isNotNegative();
this.indentSize = indentSize;
return this;
}
/**
* Sets the style to use for opening braces.
*
* @param braceStyle the style to use for opening braces
* @return this
* @throws NullPointerException if braceStyle is null
*/
public ToJsonString setBraceStyle(BraceStyle braceStyle)
throws NullPointerException
{
Preconditions.requireThat(braceStyle, "braceStyle may not be null").isNotNull();
this.braceStyle = braceStyle;
return this;
}
/**
* Uses Reflection to associate the names of all fields with their values. This method does not process superclass
* properties.
*
* @param clazz the class whose fields to process
* @param obj the object whose values to read
* @return this
* @throws NullPointerException if clazz or obj are null
* @throws IllegalArgumentException if the specified object is not an instance of the class or interface declaring the
* underlying field (or a subclass or implementor thereof)
*/
public ToJsonString putAllFields(final Class> clazz, final Object obj)
throws NullPointerException, IllegalArgumentException
{
Preconditions.requireThat(clazz, "clazz may not be null").isNotNull();
Preconditions.requireThat(obj, "obj may not be null").isNotNull();
if (!clazz.isAssignableFrom(obj.getClass()))
throw new IllegalArgumentException("obj must be an instance of " + clazz);
AccessController.doPrivileged(new PrivilegedAction()
{
@Override
public Void run()
{
try
{
for (Field field: clazz.getDeclaredFields())
{
field.setAccessible(true);
put(field.getName(), field.get(obj));
}
}
catch (IllegalAccessException e)
{
throw new AssertionError(e);
}
return null;
}
});
return this;
}
/**
* Associates the specified value with the specified key. If the key was already associated with a value, the old
* value is replaced by the specified value. If {@code value} is {@code null}, the string {@code "null"} is used.
*
* @param key the key
* @param value the value
* @return this
*/
public ToJsonString put(String key, Object value)
{
Preconditions.requireThat(key, "key may not be null").isNotNull();
map.put(key, value);
return this;
}
@Override
public String toString()
{
switch (braceStyle)
{
case NEW_LINE:
{
this.builder.append("\n{\n");
break;
}
case SAME_LINE:
{
this.builder.append(" {\n");
break;
}
default:
throw new AssertionError("Unexpected braceStyle: " + braceStyle);
}
String separator = "";
String indent = Strings.repeat(" ", indentSize);
for (Entry entry: map.entrySet())
{
builder.append(separator).append(indent).append("\"").append(entry.getKey()).append("\": ");
Object value = entry.getValue();
if (value instanceof String)
builder.append("\"");
if (value == null)
builder.append("null");
else if (value.getClass().isArray())
{
String arrayValue;
if (value instanceof Object[])
arrayValue = Arrays.toString((Object[]) value);
else if (value instanceof byte[])
arrayValue = Arrays.toString((byte[]) value);
else if (value instanceof short[])
arrayValue = Arrays.toString((short[]) value);
else if (value instanceof int[])
arrayValue = Arrays.toString((int[]) value);
else if (value instanceof long[])
arrayValue = Arrays.toString((long[]) value);
else if (value instanceof char[])
arrayValue = Arrays.toString((char[]) value);
else if (value instanceof float[])
arrayValue = Arrays.toString((float[]) value);
else if (value instanceof double[])
arrayValue = Arrays.toString((double[]) value);
else if (value instanceof boolean[])
arrayValue = Arrays.toString((boolean[]) value);
else
throw new AssertionError("Unknown array type: " + value.getClass().getName());
builder.append(arrayValue.replace("\n", "\n" + indent));
}
else
builder.append(value.toString().replace("\n", "\n" + indent));
if (value instanceof String)
builder.append("\"");
separator = ",\n";
}
return builder.append("\n}").toString();
}
}