package org.jsondoc.core.util; import java.lang.reflect.Field; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.jsondoc.core.annotation.ApiObjectField; import org.jsondoc.core.pojo.JSONDocTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class JSONDocTemplateBuilder { private static final Logger log = LoggerFactory.getLogger(JSONDocTemplateBuilder.class); private static final Map<Class<?>, Class<?>> primitives = new HashMap<Class<?>, Class<?>>(); static { primitives.put(boolean.class, Boolean.class); primitives.put(byte.class, Byte.class); primitives.put(char.class, String.class); primitives.put(double.class, Double.class); primitives.put(float.class, Float.class); primitives.put(int.class, Integer.class); primitives.put(long.class, Long.class); primitives.put(short.class, Short.class); primitives.put(void.class, Void.class); } public static JSONDocTemplate build(Class<?> clazz, Set<Class<?>> jsondocObjects) { final JSONDocTemplate jsonDocTemplate = new JSONDocTemplate(); if(jsondocObjects.contains(clazz)) { try { Set<JSONDocFieldWrapper> fields = getAllDeclaredFields(clazz); for (JSONDocFieldWrapper jsondocFieldWrapper : fields) { Field field = jsondocFieldWrapper.getField(); String fieldName = field.getName(); ApiObjectField apiObjectField = field.getAnnotation(ApiObjectField.class); if (apiObjectField != null && !apiObjectField.name().isEmpty()) { fieldName = apiObjectField.name(); } Object value; // This condition is to avoid StackOverflow in case class "A" // contains a field of type "A" if (field.getType().equals(clazz) || (apiObjectField != null && !apiObjectField.processtemplate())) { value = getValue(Object.class, field.getGenericType(), fieldName, jsondocObjects); } else { value = getValue(field.getType(), field.getGenericType(), fieldName, jsondocObjects); } jsonDocTemplate.put(fieldName, value); } } catch (Exception e) { log.error("Error in JSONDocTemplate creation for class [" + clazz.getCanonicalName() + "]", e); } } return jsonDocTemplate; } private static Object getValue(Class<?> fieldClass, Type fieldGenericType, String fieldName, Set<Class<?>> jsondocObjects) { if (fieldClass.isPrimitive()) { return getValue(wrap(fieldClass), null, fieldName, jsondocObjects); } else if (Map.class.isAssignableFrom(fieldClass)) { return new HashMap<Object, Object>(); } else if (Number.class.isAssignableFrom(fieldClass)) { return new Integer(0); } else if (String.class.isAssignableFrom(fieldClass) || fieldClass.isEnum()) { return new String(""); } else if (Boolean.class.isAssignableFrom(fieldClass)) { return new Boolean("true"); } else if (fieldClass.isArray() || Collection.class.isAssignableFrom(fieldClass)) { return new ArrayList<Object>(); } else { return build(fieldClass, jsondocObjects); } } private static Set<JSONDocFieldWrapper> getAllDeclaredFields(Class<?> clazz) { Set<JSONDocFieldWrapper> fields = new TreeSet<JSONDocFieldWrapper>(); List<Field> declaredFields = new ArrayList<Field>(); if (clazz.isEnum()) { return fields; } else { declaredFields.addAll(Arrays.asList(clazz.getDeclaredFields())); } for (Field field : declaredFields) { if (field.isAnnotationPresent(ApiObjectField.class)) { ApiObjectField annotation = field.getAnnotation(ApiObjectField.class); fields.add(new JSONDocFieldWrapper(field, annotation.order())); } else { fields.add(new JSONDocFieldWrapper(field, Integer.MAX_VALUE)); } } if (clazz.getSuperclass() != null) { fields.addAll(getAllDeclaredFields(clazz.getSuperclass())); } return fields; } @SuppressWarnings("unchecked") private static <T> Class<T> wrap(Class<T> clazz) { return clazz.isPrimitive() ? (Class<T>) primitives.get(clazz) : clazz; } }