/*
* 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 cc.plural.jsonij.marshal;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import cc.plural.jsonij.JSON;
import cc.plural.jsonij.Value;
import cc.plural.jsonij.marshal.JavaMarshaler.CycleDetector;
import cc.plural.jsonij.marshal.annotation.JSONCollector;
import cc.plural.jsonij.marshal.annotation.JSONEncoder;
import cc.plural.jsonij.marshal.codec.JSONValueCodec;
import cc.plural.jsonij.marshal.codec.JSONValueCodecStore;
import cc.plural.jsonij.marshal.codec.JSONValueCodecStore.JSONValueCodecHelper;
import cc.plural.jsonij.reflect.ClassProperty;
import cc.plural.jsonij.reflect.ClassProperty.ClassPropertyAccessor;
import cc.plural.jsonij.reflect.Inspection;
import cc.plural.jsonij.reflect.ReflectType;
/**
*
* @author jmarsden
*/
public class JavaMarshalerObjects {
protected JavaMarshaler marshaler;
public JavaMarshalerObjects(JavaMarshaler marshaler) {
this.marshaler = marshaler;
}
public Value marshalJavaObject(Object o, CycleDetector cycleDetector) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, JSONMarshalerException {
Class<?> objectClass = o.getClass();
// Check for JSONEncoder Annotation
// Method[] methods = objectClass.getDeclaredMethods();
// for (Method method : methods) {
// if (method.getAnnotation(JSONEncoder.class) != null) {
// // TODO: Encode using method.
// }
// }
//
// Field[] fields = objectClass.getFields();
// for (Field field : fields) {
// if (field.getAnnotation(JSONCollector.class) != null) {
// }
// }
// Find an object inspector
Inspection inspection = ReflectType.getInspection(objectClass);
HashMap<String, Value> valueCollector = new HashMap<String, Value>();
List<ClassProperty> properties = inspection.getProperties();
Value value;
int propCount = 0;
for (ClassProperty property : properties) {
// if(property.isCollector()) {
// continue;
// }
ClassPropertyAccessor accessor = property.getAccessor();
if (accessor == null || !accessor.canAccess()) {
continue;
}
if (accessor.fieldType()) {
try {
Field field = property.getAccessor().getField();
value = marshalObjectFieldValue(field, o, cycleDetector);
if (value == null) {
continue;
}
} catch (Exception ex) {
ex.printStackTrace();
value = new JSON.String(ex.toString());
}
} else if (accessor.methodType()) {
try {
Method method = property.getAccessor().getMethod();
value = marshalObjectMethodValue(method, o, cycleDetector);
if (value == null) {
continue;
}
} catch (Exception ex) {
value = new JSON.String(ex.toString());
}
} else {
value = JSON.NULL;
}
propCount++;
valueCollector.put(property.getPropertyName(), value);
}
if (inspection.hasInnerList()) {
if (JSONMarshaler.ALWAYS_USE_INNER_PROPERTY || propCount > 0) {
valueCollector.put(JSONMarshaler.INNER_ARRAY_PROPERTY, marshaler.marshalJavaList(o, cycleDetector));
} else {
return marshaler.marshalJavaList(o, cycleDetector);
}
}
if (inspection.hasInnerMap()) {
if (JSONMarshaler.ALWAYS_USE_INNER_PROPERTY || propCount > 0) {
valueCollector.put(JSONMarshaler.INNER_OBJECT_PROPERTY, marshaler.marshalJavaMap(o, cycleDetector));
} else {
return marshaler.marshalJavaMap(o, cycleDetector);
}
}
if (valueCollector.isEmpty()) {
return null;
} else {
JSON.Object<JSON.String, Value> marshaledObject = new JSON.Object<JSON.String, Value>();
Iterator<String> keySetIterator = valueCollector.keySet().iterator();
while (keySetIterator.hasNext()) {
String key = keySetIterator.next();
marshaledObject.put(new JSON.String(key), valueCollector.get(key));
}
if (inspection.hasCollectors()) {
for(ClassProperty collector: inspection.getCollectors()){
//collector.getMutator().fire(o, valueCollector);
}
}
return marshaledObject;
}
}
protected Value marshalObjectMethodValue(Method method, Object o, CycleDetector cycleDetector) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, JSONMarshalerException {
Value value;
Object marshaledObject = method.invoke(o);
if (marshaledObject == null) {
value = null;
} else {
int hashCode = marshaledObject.hashCode();
if (marshaledObject.getClass() == Boolean.class
|| marshaledObject.getClass() == Byte.class
|| marshaledObject.getClass() == Short.class
|| marshaledObject.getClass() == Integer.class
|| marshaledObject.getClass() == Float.class
|| marshaledObject.getClass() == Double.class
|| marshaledObject.getClass() == Long.class
|| marshaledObject.getClass() == String.class) {
value = marshaler.marshalAnyObject(marshaledObject, cycleDetector.cloneCycleDetector());
} else if (!cycleDetector.hashDetected(hashCode) || cycleDetector.getHashCount(hashCode) < JSONMarshaler.getCycleLevels()) {
cycleDetector.addHash(hashCode);
value = marshaler.marshalAnyObject(marshaledObject, cycleDetector.cloneCycleDetector());
} else {
value = null;
}
}
return value;
}
protected Value marshalObjectFieldValue(Field field, Object o, CycleDetector cycleDetector) throws IllegalArgumentException, IllegalAccessException, JSONMarshalerException {
Value value = null;
Object marshaledObject = field.get(o);
if (marshaledObject == null) {
value = null;
} else {
int hashCode = marshaledObject.hashCode();
if (marshaledObject.getClass() == Boolean.class
|| marshaledObject.getClass() == Byte.class
|| marshaledObject.getClass() == Short.class
|| marshaledObject.getClass() == Integer.class
|| marshaledObject.getClass() == Float.class
|| marshaledObject.getClass() == Double.class
|| marshaledObject.getClass() == Long.class
|| marshaledObject.getClass() == String.class) {
value = marshaler.marshalAnyObject(marshaledObject, cycleDetector.cloneCycleDetector());
} else if (!cycleDetector.hashDetected(hashCode) || cycleDetector.getHashCount(hashCode) < JSONMarshaler.getCycleLevels()) {
cycleDetector.addHash(hashCode);
value = marshaler.marshalAnyObject(marshaledObject, cycleDetector.cloneCycleDetector());
} else {
value = null;
}
}
return value;
}
}