/*
* Copyright 2011 jmarsden.
*
* 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.
* under the License.
*/
package jsonij.json.marshal;
import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import jsonij.json.JSON;
import jsonij.json.Value;
/**
*
* @author jmarsden
*/
public class JavaMarshaler {
public enum TYPE {
BOOLEAN,
NUMERIC,
STRING,
ARRAY,
LIST,
OBJECT,
MAP,
ENUM,
UNKOWN
}
JavaObjectMarshaler javaObjectMarshaler;
public JavaMarshaler() {
javaObjectMarshaler = new JavaObjectMarshaler(this);
}
public Value marshalObject(Object o) {
CycleDetector cycleDetector = new CycleDetector();
return marshalAnyObject(o, cycleDetector);
}
public Value marshalObject(boolean[] a) {
int size = 0;
if (( size = Array.getLength(a) ) == 0) {
return new JSON.Array<JSON.Numeric>();
}
JSON.Array<JSON.Boolean> marshaledArray = new JSON.Array<JSON.Boolean>();
for (int i = 0; i < size; i++) {
if (a[i]) {
marshaledArray.add(JSON.TRUE);
} else {
marshaledArray.add(JSON.FALSE);
}
}
return marshaledArray;
}
public Value marshalObject(Boolean[] a) {
int size = 0;
if (( size = Array.getLength(a) ) == 0) {
return new JSON.Array<JSON.Numeric>();
}
JSON.Array<JSON.Boolean> marshaledArray = new JSON.Array<JSON.Boolean>();
for (int i = 0; i < size; i++) {
if (a[i]) {
marshaledArray.add(JSON.TRUE);
} else {
marshaledArray.add(JSON.FALSE);
}
}
return marshaledArray;
}
public Value marshalObject(int[] a) {
int size = 0;
if (( size = Array.getLength(a) ) == 0) {
return new JSON.Array<JSON.Numeric>();
}
JSON.Array<JSON.Numeric> marshaledArray = new JSON.Array<JSON.Numeric>();
for (int i = 0; i < size; i++) {
marshaledArray.add(new JSON.Numeric(a[i]));
}
return marshaledArray;
}
public Value marshalObject(Integer[] a) {
int size = 0;
if (( size = Array.getLength(a) ) == 0) {
return new JSON.Array<JSON.Numeric>();
}
JSON.Array<JSON.Numeric> marshaledArray = new JSON.Array<JSON.Numeric>();
for (int i = 0; i < size; i++) {
marshaledArray.add(new JSON.Numeric(a[i]));
}
return marshaledArray;
}
public Value marshalObject(char[] a) {
int size = 0;
if (( size = Array.getLength(a) ) == 0) {
return new JSON.Array<JSON.Numeric>();
}
JSON.Array<JSON.String> marshaledArray = new JSON.Array<JSON.String>();
for (int i = 0; i < size; i++) {
marshaledArray.add(new JSON.String("" + a[i]));
}
return marshaledArray;
}
public Value marshalObject(Character[] a) {
int size = 0;
if (( size = Array.getLength(a) ) == 0) {
return new JSON.Array<JSON.Numeric>();
}
JSON.Array<JSON.String> marshaledArray = new JSON.Array<JSON.String>();
for (int i = 0; i < size; i++) {
marshaledArray.add(new JSON.String("" + a[i]));
}
return marshaledArray;
}
public Value marshalObject(double[] a) {
int size = 0;
if (( size = Array.getLength(a) ) == 0) {
return new JSON.Array<JSON.Numeric>();
}
JSON.Array<JSON.Numeric> marshaledArray = new JSON.Array<JSON.Numeric>();
for (int i = 0; i < size; i++) {
marshaledArray.add(new JSON.Numeric(a[i]));
}
return marshaledArray;
}
public Value marshalObject(Double[] a) {
int size = 0;
if (( size = Array.getLength(a) ) == 0) {
return new JSON.Array<JSON.Numeric>();
}
JSON.Array<JSON.Numeric> marshaledArray = new JSON.Array<JSON.Numeric>();
for (int i = 0; i < size; i++) {
marshaledArray.add(new JSON.Numeric(a[i]));
}
return marshaledArray;
}
public Value marshalObject(float[] a) {
int size = 0;
if (( size = Array.getLength(a) ) == 0) {
return new JSON.Array<JSON.Numeric>();
}
JSON.Array<JSON.Numeric> marshaledArray = new JSON.Array<JSON.Numeric>();
for (int i = 0; i < size; i++) {
marshaledArray.add(new JSON.Numeric(a[i]));
}
return marshaledArray;
}
public Value marshalObject(Float[] a) {
int size = 0;
if (( size = Array.getLength(a) ) == 0) {
return new JSON.Array<JSON.Numeric>();
}
JSON.Array<JSON.Numeric> marshaledArray = new JSON.Array<JSON.Numeric>();
for (int i = 0; i < size; i++) {
marshaledArray.add(new JSON.Numeric(a[i]));
}
return marshaledArray;
}
public Value marshalObject(short[] a) {
int size = 0;
if (( size = Array.getLength(a) ) == 0) {
return new JSON.Array<JSON.Numeric>();
}
JSON.Array<JSON.Numeric> marshaledArray = new JSON.Array<JSON.Numeric>();
for (int i = 0; i < size; i++) {
marshaledArray.add(new JSON.Numeric(a[i]));
}
return marshaledArray;
}
public Value marshalObject(Short[] a) {
int size = 0;
if (( size = Array.getLength(a) ) == 0) {
return new JSON.Array<JSON.Numeric>();
}
JSON.Array<JSON.Numeric> marshaledArray = new JSON.Array<JSON.Numeric>();
for (int i = 0; i < size; i++) {
marshaledArray.add(new JSON.Numeric(a[i]));
}
return marshaledArray;
}
public Value marshalObject(long[] a) {
int size = 0;
if (( size = Array.getLength(a) ) == 0) {
return new JSON.Array<JSON.Numeric>();
}
JSON.Array<JSON.Numeric> marshaledArray = new JSON.Array<JSON.Numeric>();
for (int i = 0; i < size; i++) {
marshaledArray.add(new JSON.Numeric(a[i]));
}
return marshaledArray;
}
public Value marshalObject(Long[] a) {
int size = 0;
if (( size = Array.getLength(a) ) == 0) {
return new JSON.Array<JSON.Numeric>();
}
JSON.Array<JSON.Numeric> marshaledArray = new JSON.Array<JSON.Numeric>();
for (int i = 0; i < size; i++) {
marshaledArray.add(new JSON.Numeric(a[i]));
}
return marshaledArray;
}
public Value marshalObject(String[] a) {
int size = 0;
if (( size = Array.getLength(a) ) == 0) {
return new JSON.Array<JSON.Numeric>();
}
JSON.Array<JSON.String> marshaledArray = new JSON.Array<JSON.String>();
for (int i = 0; i < size; i++) {
marshaledArray.add(new JSON.String(a[i]));
}
return marshaledArray;
}
public Value marshalObject(Object[] a) {
int size = 0;
if (( size = Array.getLength(a) ) == 0) {
return new JSON.Array<JSON.Numeric>();
}
CycleDetector cycleDetector = new CycleDetector();
JSON.Array<Value> marshaledArray = new JSON.Array<Value>();
for (int i = 0; i < size; i++) {
Value marshaledObject = marshalJavaObject(a[i], cycleDetector);
if(marshaledObject != null) {
marshaledArray.add(marshaledObject);
} else {
marshaledArray.add(JSON.NULL);
}
}
return marshaledArray;
}
protected TYPE inspectObjectType(Class<?> c) {
if (c == Boolean.class || c == boolean.class) {
return TYPE.BOOLEAN;
}
if (c == int.class || c == Integer.class) {
return TYPE.NUMERIC;
}
if (c == double.class || c == Double.class) {
return TYPE.NUMERIC;
}
if (c == float.class || c == Float.class) {
return TYPE.NUMERIC;
}
if (c == long.class || c == Long.class) {
return TYPE.NUMERIC;
}
if (c == short.class || c == Short.class) {
return TYPE.NUMERIC;
}
if (c.isEnum()) {
return TYPE.ENUM;
}
if (c == String.class || ( ( c == char.class || c == Character.class ) )) {
return TYPE.STRING;
}
if (c.isArray()) {
return TYPE.ARRAY;
}
// Test if Object is a List
Class<?>[] interfaces = c.getInterfaces();
for (int i = 0; i < Array.getLength(interfaces); i++) {
if (interfaces[i] == List.class) {
return TYPE.LIST;
}
}
if (javaObjectMarshaler.isObjectType(c)) {
return TYPE.OBJECT;
}
// Test if super classes are List
Class<?> parent = c.getSuperclass();
if (parent != null) {
do {
interfaces = parent.getInterfaces();
for (int i = 0; i < Array.getLength(interfaces); i++) {
if (interfaces[i] == List.class) {
return TYPE.LIST;
}
}
} while (( parent = parent.getSuperclass() ) != null);
}
return TYPE.UNKOWN;
}
protected Value marshalAnyObject(Object o, CycleDetector cycleDetector) {
if(o == null) {
return JSON.NULL;
}
Value marshaledObject = null;
Class<?> objectClass = o.getClass();
TYPE objectType = inspectObjectType(objectClass);
switch (objectType) {
case BOOLEAN:
marshaledObject = marshalJavaBoolean(o);
break;
case NUMERIC:
marshaledObject = marshalJavaNumeric(o);
break;
case STRING:
marshaledObject = marshalJavaString(o);
break;
case ENUM:
marshaledObject = marshalJavaEnum(o);
break;
case ARRAY:
marshaledObject = marshalJavaArray(o, cycleDetector);
break;
case LIST:
marshaledObject = marshalJavaList(o, cycleDetector);
break;
case OBJECT:
marshaledObject = marshalJavaObject(o, cycleDetector);
break;
case MAP:
marshaledObject = marshalJavaMap(o, cycleDetector);
break;
case UNKOWN:
marshaledObject = new JSON.String(o.getClass().getCanonicalName() + "@" + Integer.toHexString(o.hashCode()));
}
return marshaledObject;
}
protected Value marshalJavaBoolean(Object o) {
Value value = null;
boolean marshaledBoolean = (Boolean) o;
if (marshaledBoolean) {
value = JSON.TRUE;
} else {
value = JSON.FALSE;
}
return value;
}
protected Value marshalJavaNumeric(Object o) {
Value value = null;
Number marshaledNumber = null;
marshaledNumber = (Number) o;
if (marshaledNumber != null) {
value = new JSON.Numeric(marshaledNumber);
} else {
value = JSON.NULL;
}
return value;
}
protected Value marshalJavaEnum(Object o) {
Value value = null;
if (o != null) {
String marshaledEnumeration = o.toString();
value = new JSON.String(marshaledEnumeration);
} else {
value = JSON.NULL;
}
return value;
}
protected Value marshalJavaString(Object o) {
Value value = null;
String marshaledString = (String) o;
if (marshaledString != null) {
value = new JSON.String(marshaledString);
} else {
value = JSON.NULL;
}
return value;
}
protected Value marshalJavaArray(Object o, CycleDetector cycleDetector) {
Value value = null;
if (o != null) {
JSON.Array<Value> marshaledArray = new JSON.Array<Value>();
int size = Array.getLength(o);
Class<?> type = o.getClass();
Class<?> componentType = type.getComponentType();
if (componentType == int.class || componentType == Integer.class) {
for (int i = 0; i < size; i++) {
marshaledArray.add(new JSON.Numeric(Array.getInt(o, i)));
}
} else if (componentType == double.class || componentType == Double.class) {
for (int i = 0; i < size; i++) {
marshaledArray.add(new JSON.Numeric(Array.getDouble(o, i)));
}
} else if (componentType == float.class || componentType == Float.class) {
for (int i = 0; i < size; i++) {
marshaledArray.add(new JSON.Numeric(Array.getFloat(o, i)));
}
} else if (componentType == short.class || componentType == Short.class) {
for (int i = 0; i < size; i++) {
marshaledArray.add(new JSON.Numeric(Array.getShort(o, i)));
}
} else if (componentType == long.class || componentType == Long.class) {
for (int i = 0; i < size; i++) {
marshaledArray.add(new JSON.Numeric(Array.getLong(o, i)));
}
} else {
for (int i = 0; i < size; i++) {
Object arrayValue = Array.get(o, i);
marshaledArray.add(marshalAnyObject(arrayValue, cycleDetector.cloneCycleDetector()));
}
}
value = marshaledArray;
} else {
value = JSON.NULL;
}
return value;
}
protected Value marshalJavaList(Object o, CycleDetector cycleDetector) {
Value value = null;
List<?> marshaledList = (List<?>) o;
if (marshaledList != null) {
JSON.Array<Value> marshaledArray = new JSON.Array<Value>();
Iterator<?> marshaledListIterator = marshaledList.listIterator();
Object listItem = null;
while (marshaledListIterator.hasNext()) {
listItem = marshaledListIterator.next();
if (listItem == null) {
marshaledArray.add(JSON.NULL);
continue;
}
marshaledArray.add(marshalAnyObject(listItem, cycleDetector.cloneCycleDetector()));
}
value = marshaledArray;
} else {
value = JSON.NULL;
}
return value;
}
protected Value marshalJavaMap(Object o, CycleDetector cycleDetector) {
Value value = null;
Map<?, ?> marshaledMap = (Map<?, ?>) o;
if (marshaledMap != null) {
JSON.Object<JSON.String, Value> marshaledObject = new JSON.Object<JSON.String, Value>();
Iterator<?> keySetIterator = marshaledMap.keySet().iterator();
while (keySetIterator.hasNext()) {
Object keyObject = keySetIterator.next();
Object valueObject = marshaledMap.get(keyObject);
marshaledObject.put(new JSON.String(keyObject.toString()), marshalAnyObject(valueObject, cycleDetector.cloneCycleDetector()));
}
value = marshaledObject;
} else {
value = JSON.NULL;
}
return value;
}
protected Value marshalJavaObject(Object o, CycleDetector cycleDetector) {
Value marshaledValue = javaObjectMarshaler.marshalJavaObject(o, cycleDetector);
return marshaledValue;
}
public static class CycleDetector implements Cloneable {
final HashMap<Integer, Integer> list;
public CycleDetector() {
list = new HashMap<Integer, Integer>();
}
protected CycleDetector(HashMap<Integer, Integer> list) {
this.list = list;
}
public boolean hashDetected(int hash) {
return list.containsKey(hash);
}
public int getHashCount(int hash) {
if(list.containsKey(hash)) {
return list.get(hash);
}
return 0;
}
public void addHash(int hash) {
if(!hashDetected(hash)) {
list.put(hash, 0);
} else {
Integer value = list.remove(hash);
list.put(hash, ++value);
}
}
protected CycleDetector cloneCycleDetector() {
HashMap<Integer, Integer> newHashMap = new HashMap<Integer,Integer>();
Iterator<Integer> hashSetIterator = list.keySet().iterator();
while(hashSetIterator.hasNext()) {
Integer key = hashSetIterator.next();
Integer value = list.get(key);
newHashMap.put(key, value);
}
return new CycleDetector(newHashMap);
}
@Override
protected Object clone() throws CloneNotSupportedException {
return new CycleDetector((HashMap<Integer, Integer>) list.clone());
}
}
}