/*
* 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.
*/
package cc.plural.jsonij.marshal;
import cc.plural.jsonij.JSON;
import cc.plural.jsonij.Value;
import cc.plural.jsonij.marshal.codec.JSONValueCodecStore.JSONValueCodecHelper;
import cc.plural.jsonij.parser.ParserException;
import cc.plural.jsonij.reflect.ClassProperty;
import cc.plural.jsonij.reflect.Inspection;
import cc.plural.jsonij.reflect.ReflectType;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author jmarsden
*/
public class JSONDocumentMarshaler {
public Object marshalJSONDocument(JSON json, Class<?> objectClass) throws JSONMarshalerException {
Object resultObject = null;
Value jsonRoot = json.getRoot();
if (jsonRoot.type() == Value.TYPE.OBJECT) {
JSON.Object<CharSequence, Value> jsonObjectRoot = (JSON.Object<CharSequence, Value>) jsonRoot;
resultObject = marshalJSONDocumentObject(jsonObjectRoot, objectClass);
} else if (jsonRoot.type() == Value.TYPE.ARRAY) {
JSON.Array<Value> jsonArrayRoot = (JSON.Array<Value>) jsonRoot;
resultObject = marshalJSONDocumentArray(jsonArrayRoot, objectClass);
} else {
throw new RuntimeException("Not an Object or Array Type.");
}
return resultObject;
}
public Object marshalJSONDocument(Value value, Class<?> objectClass) throws JSONMarshalerException {
Object resultObject = null;
ReflectType type = ReflectType.inspectObjectType(objectClass);
switch (type) {
case OBJECT:
if (value.type() == Value.TYPE.OBJECT) {
JSON.Object<CharSequence, Value> jsonObjectRoot = (JSON.Object<CharSequence, Value>) value;
resultObject = marshalJSONDocumentObject(jsonObjectRoot, objectClass);
} else {
// TODO
}
break;
case ARRAY:
case ARRAY_BOOLEAN:
case ARRAY_BYTE:
case ARRAY_SHORT:
case ARRAY_INTEGER:
case ARRAY_FLOAT:
case ARRAY_DOUBLE:
case ARRAY_LONG:
case ARRAY_STRING:
case ARRAY_ENUM:
if (value.type() == Value.TYPE.ARRAY) {
JSON.Array<Value> jsonArrayRoot = (JSON.Array<Value>) value;
resultObject = marshalJSONDocumentArray(jsonArrayRoot, objectClass);
} else {
// TODO: Strict
}
break;
case STRING:
if (value.type() == Value.TYPE.STRING) {
return value.toString();
}
break;
case BOOLEAN:
if (value.type() == Value.TYPE.TRUE) {
return true;
} else if (value.type() == Value.TYPE.FALSE) {
return false;
} else {
}
break;
case BYTE:
if (value.type() == Value.TYPE.NUMERIC) {
return value.getNumber().byteValue();
} else {
// TODO: Strict
}
break;
case SHORT:
if (value.type() == Value.TYPE.NUMERIC) {
return value.getNumber().shortValue();
} else {
// TODO: Strict
}
break;
case INTEGER:
if (objectClass == BigInteger.class) {
return new BigInteger(value.getString());
} else if (value.type() == Value.TYPE.NUMERIC) {
return value.getNumber().intValue();
} else {
// TODO: Strict
}
break;
case DOUBLE:
if (objectClass == BigDecimal.class) {
return new BigDecimal(value.getString());
} else if (value.type() == Value.TYPE.NUMERIC) {
return value.getNumber().doubleValue();
} else {
// TODO: Strict
}
break;
case FLOAT:
if (value.type() == Value.TYPE.NUMERIC) {
return value.getNumber().floatValue();
} else {
// TODO: Strict
}
break;
case LONG:
if (value.type() == Value.TYPE.NUMERIC) {
return value.getNumber().longValue();
} else {
// TODO: Strict
}
break;
case CLASS:
if (value.type() == Value.TYPE.STRING) {
try {
return Class.forName(value.toString());
} catch (ClassNotFoundException ex) { }
}
case UNKOWN:
default:
System.out.println("Unknown Type:" + type + " " + value);
throw new RuntimeException("Unhandled Type " + type + " " + value);
}
return resultObject;
}
public Object marshalJSONDocument(InputStream stream, Class<?> objectClass) throws JSONMarshalerException {
JSON json;
try {
json = JSON.parse(stream);
} catch (ParserException ex) {
throw new JSONMarshalerException("", ex);
} catch (IOException ex) {
throw new JSONMarshalerException("", ex);
}
return marshalJSONDocument(json, objectClass);
}
public Object marshalJSONDocument(String jsonString, Class<?> objectClass) throws JSONMarshalerException {
JSON json;
try {
json = JSON.parse(jsonString);
} catch (ParserException ex) {
throw new JSONMarshalerException("", ex);
} catch (IOException ex) {
throw new JSONMarshalerException("", ex);
}
return marshalJSONDocument(json, objectClass);
}
public Object marshalJSONDocumentObject(JSON.Object<CharSequence, Value> jsonObject, Class<?> objectClass) throws JSONMarshalerException {
Object object = null;
if (JSONMarshaler.hasCodec(objectClass)) {
JSONValueCodecHelper codecHelper = JSONMarshaler.getCodecHelper(objectClass);
try {
object = codecHelper.decode(jsonObject, objectClass);
} catch (IllegalAccessException ex) {
Logger.getLogger(JSONDocumentMarshaler.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalArgumentException ex) {
Logger.getLogger(JSONDocumentMarshaler.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvocationTargetException ex) {
Logger.getLogger(JSONDocumentMarshaler.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
try {
object = objectClass.newInstance();
} catch (InstantiationException ex) {
Logger.getLogger(JSONDocumentMarshaler.class.getName()).log(Level.SEVERE, null, ex);
throw new JSONMarshalerException("newInstance");
} catch (IllegalAccessException ex) {
Logger.getLogger(JSONDocumentMarshaler.class.getName()).log(Level.SEVERE, null, ex);
throw new JSONMarshalerException("illegalAccess");
}
ReflectType type = ReflectType.inspectObjectType(objectClass);
Inspection inspection = ReflectType.getInspection(objectClass);
boolean hasCollector = inspection.hasCollectors();
Map<CharSequence, Value> collector = null;
Map<CharSequence, Value> innerObjectCollector = null;
List<Value> innerArrayCollector = null;
if (hasCollector) {
collector = new HashMap<CharSequence, Value>();
}
if (inspection.hasInnerMap()) {
innerObjectCollector = new HashMap<CharSequence, Value>();
}
if (inspection.hasInnerList()) {
innerArrayCollector = new ArrayList<Value>();
}
for (Entry<CharSequence, Value> documentPropertyEntry : jsonObject.entrySet()) {
CharSequence key = documentPropertyEntry.getKey();
if (inspection.hasProperty(key.toString())) {
ClassProperty inspectorProperty = inspection.getProperty(key.toString());
Value documentValue = documentPropertyEntry.getValue();
try {
marshalJSONValue(documentValue, object, inspectorProperty);
} catch (IllegalAccessException ex) {
Logger.getLogger(JSONDocumentMarshaler.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalArgumentException ex) {
Logger.getLogger(JSONDocumentMarshaler.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvocationTargetException ex) {
Logger.getLogger(JSONDocumentMarshaler.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
if (hasCollector) {
collector.put(key, documentPropertyEntry.getValue());
}
if (inspection.hasInnerMap()) {
innerObjectCollector.put(key, documentPropertyEntry.getValue());
}
if (inspection.hasInnerList()) {
innerArrayCollector.add(documentPropertyEntry.getValue());
}
}
}
if (hasCollector) {
for (ClassProperty collectorProperty : inspection.getCollectors()) {
try {
collectorProperty.getMutator().fire(object, collector);
} catch (IllegalAccessException ex) {
Logger.getLogger(JSONDocumentMarshaler.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalArgumentException ex) {
Logger.getLogger(JSONDocumentMarshaler.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvocationTargetException ex) {
Logger.getLogger(JSONDocumentMarshaler.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
if (inspection.hasInnerMap()) {
}
if (inspection.hasInnerList()) {
}
}
return object;
}
public Object marshalJSONDocumentArray(JSON.Array<Value> jsonArray, Class<?> objectClass) throws JSONMarshalerException {
int size = jsonArray.size();
ReflectType type = ReflectType.inspectObjectType(objectClass);
if (type == ReflectType.OBJECT) {
return marshalJSONDocumentList(jsonArray, objectClass);
} else {
Class<?> componentClass = objectClass.getComponentType();
ReflectType componentType = ReflectType.inspectObjectType(componentClass);
Object array = Array.newInstance(componentClass, size);
for (int i = 0; i < size; i++) {
Value value = jsonArray.get(i);
if (value.getValueType() == Value.TYPE.OBJECT) {
Array.set(array, i, marshalJSONDocumentObject((JSON.Object<CharSequence, Value>) value, componentClass));
} else if (value.getValueType() == Value.TYPE.ARRAY) {
Array.set(array, i, marshalJSONDocumentArray((JSON.Array<Value>) value, componentClass));
} else if (componentType == ReflectType.INTEGER) {
Array.set(array, i, jsonArray.get(i).getNumber().intValue());
} else if (componentType == ReflectType.FLOAT) {
Array.set(array, i, jsonArray.get(i).getNumber().floatValue());
} else if (componentType == ReflectType.DOUBLE) {
Array.set(array, i, jsonArray.get(i).getNumber().doubleValue());
} else if (componentType == ReflectType.BYTE) {
Array.set(array, i, jsonArray.get(i).getNumber().byteValue());
} else if (componentType == ReflectType.BOOLEAN) {
Array.set(array, i, jsonArray.get(i).getBoolean());
} else if (componentType == ReflectType.STRING) {
Array.set(array, i, jsonArray.get(i).getString());
} else {
}
}
return array;
}
}
public List<?> marshalJSONDocumentList(JSON.Array<Value> jsonArray, Class<?> objectClass) throws JSONMarshalerException {
return null;
}
public Map<?, ?> marshalJSONDocumentMap(JSON.Object<CharSequence, Value> jsonMap, Type type) throws JSONMarshalerException {
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type[] parameterTypeArray = parameterizedType.getActualTypeArguments();
if (parameterTypeArray != null && parameterTypeArray.length == 2) {
Class<?> keyClass = null;
if (parameterTypeArray[0] instanceof Class) {
keyClass = (Class<?>) parameterTypeArray[0];
}
Class<?> valueClass = null;
if (parameterTypeArray[1] instanceof Class) {
valueClass = (Class<?>) parameterTypeArray[1];
} else if (parameterTypeArray[1] instanceof ParameterizedType) {
ParameterizedType valueType = (ParameterizedType) parameterTypeArray[1];
valueClass = (Class<?>) valueType.getRawType();
}
// if(keyClass == null || valueClass == null) {
// return null;
// }
//
Map<CharSequence, Object> returnMap = new HashMap();
Iterator<CharSequence> keySetIterator = jsonMap.keySet().iterator();
while (keySetIterator.hasNext()) {
CharSequence keyValue = keySetIterator.next();
Value value = jsonMap.get(keyValue);
Object o = marshalJSONDocument(value, valueClass);
returnMap.put(keyValue, o);
}
return returnMap;
} else {
throw new RuntimeException("Beef this up");
}
}
System.out.println(jsonMap);
Iterator<CharSequence> keySet = jsonMap.keySet().iterator();
while (keySet.hasNext()) {
CharSequence key = keySet.next();
Value v = jsonMap.get(key);
}
return null;
}
private void marshalJSONValue(Value value, Object object, ClassProperty inspectorProperty) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, JSONMarshalerException {
ClassProperty.ClassPropertyMutator mutator = inspectorProperty.getMutator();
ReflectType type = ReflectType.inspectObjectType(mutator.getType());
switch (type) {
case BOOLEAN:
mutator.fire(object, value.getBoolean());
return;
case BYTE:
mutator.fire(object, value.getNumber().byteValue());
return;
case SHORT:
mutator.fire(object, value.getNumber().shortValue());
return;
case INTEGER:
mutator.fire(object, value.getNumber().intValue());
return;
case FLOAT:
mutator.fire(object, value.getNumber().floatValue());
return;
case LONG:
mutator.fire(object, value.getNumber().longValue());
return;
case STRING:
mutator.fire(object, value.getString());
return;
case ARRAY:
case ARRAY_BOOLEAN:
case ARRAY_BYTE:
case ARRAY_SHORT:
case ARRAY_INTEGER:
case ARRAY_FLOAT:
case ARRAY_DOUBLE:
case ARRAY_LONG:
case ARRAY_STRING:
case ARRAY_ENUM:
mutator.fire(object, marshalJSONDocumentArray((JSON.Array<Value>) value, mutator.getType()));
return;
case OBJECT:
Object propertyObject = marshalJSONDocument(value, mutator.getType());
mutator.fire(object, propertyObject);
return;
case MAP:
Map<?, ?> propertyMap = marshalJSONDocumentMap((JSON.Object<CharSequence, Value>) value, mutator.getGenericType());
mutator.fire(object, propertyMap);
return;
case UNKOWN:
Object propertyUnknown = marshalJSONDocument(value, mutator.getType());
mutator.fire(object, propertyUnknown);
default:
System.out.println("Unknown Type:" + type + " " + value);
throw new RuntimeException("Unhandled Type " + type + " " + value);
}
}
}