Desenvolvi estas classes baseadas na biblioteca FlexJson: http://flexjson.sourceforge.net/ . Fiz algumas alterações que deixou a biblioteca bem menor. Mas, minha motivação principal foi que eu pudesse utilizar a biblioteca na versão 1.4 do Java. Ao todo, a biblioteca ficou com apenas quatro classes: ChainedIterator, ChainedSet, JSONSerializer, ObjectVisitor. Vou colocar o código de todas elas, e também um exemplo de uso.
Código da classse ChainedIterator
import java.util.Iterator;Código da classe ChainedSet
import java.util.Iterator;
import java.util.Set;
public class ChainedIterator implements Iterator {
Iterator[] iterators;
int current = 0;
public ChainedIterator(Set sets) {
Object[] arraySets = sets.toArray();
iterators = new Iterator[sets.size()];
for( int i = 0; i < sets.size(); i++ ) {
iterators[i] = ((Set)arraySets[i]).iterator();
}
}
public boolean hasNext() {
if( iterators[current].hasNext() ) {
return true;
} else {
current++;
return current < iterators.length && iterators[current].hasNext();
}
}
public Object next() {
return iterators[current].next();
}
public void remove() {
iterators[current].remove();
}
}
import java.util.Set;Código da classe JSONSerializer
import java.util.HashSet;
import java.util.Iterator;
import java.util.Collection;
import java.util.TreeSet;
public class ChainedSet implements Set {
Set parent;
Set child;
public ChainedSet(Set parent) {
this.parent = parent;
this.child = new HashSet();
}
public int size() {
return this.child.size() + parent.size();
}
public boolean isEmpty() {
return this.child.isEmpty() && parent.isEmpty();
}
public boolean contains(Object o) {
return child.contains(o) || parent.contains(o);
}
public Iterator iterator() {
Set sets = new TreeSet();
sets.add(child);
sets.add(parent);
return new ChainedIterator(sets);
}
public Object[] toArray() {
Object[] carr = child.toArray();
Object[] parr = parent.toArray();
Object[] combined = new Object[ carr.length + parr.length ];
System.arraycopy( carr, 0, combined, 0, carr.length );
System.arraycopy( parr, 0, combined, carr.length, parr.length );
return combined;
}
public Object[] toArray(Object[] a) {
throw new IllegalStateException( "Not implemeneted" );
}
public boolean add(Object o) {
return child.add( o );
}
public boolean remove(Object o) {
return child.remove( o );
}
public boolean containsAll(Collection c) {
return child.containsAll(c) || parent.containsAll(c);
}
public boolean addAll(Collection c) {
return child.addAll( c );
}
public boolean retainAll(Collection c) {
return child.retainAll( c );
}
public boolean removeAll(Collection c) {
return child.removeAll( c );
}
public void clear() {
child.clear();
}
public Set getParent() {
return parent;
}
}
import java.util.ArrayList;Código da classe ObjectVisitor
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JSONSerializer {
public final static char[] HEX = "0123456789ABCDEF".toCharArray();
List pathExpressions = new ArrayList();
Map transformations = new HashMap();
public JSONSerializer() {
}
public String serialize( String rootName, Object target ) {
return new ObjectVisitor().visit( rootName, target );
}
public String serialize( Object target ) {
return new ObjectVisitor().visit( target );
}
public String prettyPrint( Object target ) {
return new ObjectVisitor( true ).visit( target );
}
public String prettyPrint( String rootName, Object target ) {
return new ObjectVisitor( true ).visit( rootName, target );
}
}
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
public class ObjectVisitor {
protected StringBuffer builder;
protected boolean prettyPrint = false;
private int amount = 0;
private boolean insideArray = false;
protected ObjectVisitor() {
builder = new StringBuffer();
}
public ObjectVisitor(boolean prettyPrint) {
this();
this.prettyPrint = prettyPrint;
}
public String visit( Object target ) {
json( target );
return builder.toString();
}
public String visit( String rootName, Object target ) {
beginObject();
string(rootName);
add(':');
json( target );
endObject();
return builder.toString();
}
private void numberToString(Number n) {
if (n != null && testValidity(n)) {
String s = n.toString();
if (s.indexOf('.') > 0 && s.indexOf('e') < 0 && s.indexOf('E') < 0) {
while (s.endsWith("0")) {
s = s.substring(0, s.length() - 1);
}
if (s.endsWith(".")) {
s = s.substring(0, s.length() - 1);
}
}
add(s);
}else{
add("0");
}
}
private boolean testValidity(Object o) {
if (o != null) {
if (o instanceof Double) {
if (((Double)o).isInfinite() || ((Double)o).isNaN()) {
return false;
}
} else if (o instanceof Float) {
if (((Float)o).isInfinite() || ((Float)o).isNaN()) {
return false;
}
}
}
return true;
}
private void json(Object object) {
if (object == null) add("null");
else if (object instanceof Class)
string( ((Class)object).getName() );
else if (object instanceof Boolean)
bool( ((Boolean) object) );
else if (object instanceof String)
string(object);
else if (object instanceof Character)
string(object);
else if (object instanceof Number)
numberToString((Number) object);
else if (object instanceof Map)
map( (Map)object);
else if (object.getClass().isArray())
array( object );
else if( object instanceof Date)
date( (Date)object );
else if (object instanceof Collection)
array(((Collection) object).iterator() );
else
bean( object );
}
private void map(Map map) {
beginObject();
Iterator it = map.keySet().iterator();
boolean firstField = true;
while (it.hasNext()) {
Object key = it.next();
int len = builder.length();
add( key, map.get(key), firstField );
if( len < builder.length() ) {
firstField = false;
}
}
endObject();
}
private void array(Iterator it) {
beginArray();
while (it.hasNext()) {
if( prettyPrint ) {
addNewline();
}
addArrayElement( it.next(), it.hasNext() );
}
endArray();
}
private void array(Object object) {
beginArray();
int length = Array.getLength(object);
for (int i = 0; i < length; ++i) {
if( prettyPrint ) {
addNewline();
}
addArrayElement( Array.get(object, i), i < length - 1 );
}
endArray();
}
private void addArrayElement(Object object, boolean isLast ) {
int len = builder.length();
json( object );
if( len < builder.length() ) { // make sure we at least added an element.
if ( isLast ) add(',');
}
}
private void bool(Boolean b) {
add( b.booleanValue() ? "true" : "false" );
}
private void string(Object obj) {
add('"');
CharacterIterator it = new StringCharacterIterator(obj.toString());
for (char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
if (c == '"') add("\\\"");
else if (c == '\\') add("\\\\");
else if (c == '\b') add("\\b");
else if (c == '\f') add("\\f");
else if (c == '\n') add("\\n");
else if (c == '\r') add("\\r");
else if (c == '\t') add("\\t");
else if (Character.isISOControl(c)) {
unicode(c);
} else {
add(c);
}
}
add('"');
}
private void date(Date date) {
builder.append( date.getTime());
}
private ChainedSet visits = new ChainedSet( Collections.EMPTY_SET );
protected void bean(Object bean) {
if( !visits.contains( bean ) ) {
visits = new ChainedSet( visits );
visits.add( bean );
beginObject();
try {
Class klass = bean.getClass();
Method[] methods = klass.getMethods();
boolean firstField = true;
for (int i = 0; i < methods.length; i += 1) {
Method method = methods[i];
if (Modifier.isPublic(method.getModifiers())) {
String name = method.getName();
String key = "";
boolean invoke = false;
if (name.startsWith("get")) {
invoke = true;
key = name.substring(3);
} else if (name.startsWith("is")) {
key = name.substring(2);
invoke = true;
}
if (key.length() > 0){
key = String.valueOf(key.charAt(0)).toLowerCase() + key.substring(1);
}
if (invoke) {
Object value = method.invoke(bean, (Object[])null);
if( !visits.contains( value ) ) {
add(key, value, firstField);
firstField = false;
}
}
}
}
} catch( Exception e ) {
}
endObject();
visits = (ChainedSet) visits.getParent();
}
}
protected boolean addComma(boolean firstField) {
if ( !firstField ) {
add(',');
} else {
firstField = false;
}
return firstField;
}
protected void beginObject() {
if( prettyPrint ) {
if( insideArray ) {
indent( amount );
}
amount += 4;
}
add( '{' );
}
protected void endObject() {
if( prettyPrint ) {
addNewline();
amount -= 4;
indent( amount );
}
add( '}' );
}
private void beginArray() {
if( prettyPrint ) {
amount += 4;
insideArray = true;
}
add('[');
}
private void endArray() {
if( prettyPrint ) {
addNewline();
amount -= 4;
insideArray = false;
indent( amount );
}
add(']');
}
protected void add( char c ) {
builder.append( c );
}
private void indent(int amount) {
for( int i = 0; i < amount; i++ ) {
builder.append( " " );
}
}
private void addNewline() {
builder.append("\n");
}
protected void add( Object value ) {
builder.append( value );
}
protected void add(Object key, Object value, boolean prependComma) {
int start = builder.length();
addComma( prependComma );
addAttribute( key );
int len = builder.length();
json( value );
if( len == builder.length() ) {
builder.delete( start, len ); // erase the attribute key we didn't output anything.
}
}
private void addAttribute(Object key) {
if( prettyPrint ) {
addNewline();
indent( amount );
}
builder.append("\"");
builder.append( key );
builder.append( "\"" );
builder.append( ":" );
if( prettyPrint ) {
builder.append(" ");
}
}
private void unicode(char c) {
add("\\u");
int n = c;
for (int i = 0; i < 4; ++i) {
int digit = (n & 0xf000) >> 12;
add(JSONSerializer.HEX[digit]);
n <<= 4;
}
}
}