package com.quemb.qmbform.annotation; import com.quemb.qmbform.descriptor.FormDescriptor; import com.quemb.qmbform.descriptor.FormOptionsObject; import com.quemb.qmbform.descriptor.RowDescriptor; import com.quemb.qmbform.descriptor.SectionDescriptor; import com.quemb.qmbform.descriptor.Value; import android.content.Context; import android.util.Log; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; /** * Created by tonimoeckel on 14.07.14. */ public class FormDescriptorAnnotationFactory { private static final String TAG = "AnnotationFactory"; private Context mContext; public FormDescriptorAnnotationFactory(Context context) { mContext = context; } public Context getContext() { return mContext; } public FormDescriptor createFormDescriptorFromAnnotatedClass(Object object) { return createFormDescriptorFromAnnotatedClass(object, null); } /** * Added cellConfig parameter */ public FormDescriptor createFormDescriptorFromAnnotatedClass(Object object, HashMap<String, Object> cellConfig) { Class objClass = object.getClass(); List<Field> declaredFields = getAllFields(new ArrayList<Field>(), objClass); return createFormDescriptorFromFields(declaredFields, object, cellConfig); } public FormDescriptor createFormDescriptorFromFields(List<Field> fields, Object object, HashMap<String, Object> cellConfig) { FormDescriptor formDescriptor = FormDescriptor.newInstance(); if (cellConfig != null) formDescriptor.setCellConfig(cellConfig); List<Field> formFields = new ArrayList<Field>(); List<Section> sections = new ArrayList<Section>(); /** * Get all annotated class fields */ for (Field field : fields) { if (field.getAnnotation(FormElement.class) != null) { formFields.add(field); } } Collections.sort(formFields, new Comparator<Field>() { @Override public int compare(Field lhs, Field rhs) { FormElement annotationLhs = lhs.getAnnotation(FormElement.class); FormElement annotationRhs = rhs.getAnnotation(FormElement.class); if (annotationLhs.sortId() > annotationRhs.sortId()) { return 1; } else if (annotationLhs.sortId() < annotationRhs.sortId()) { return -1; } return 0; } }); /** * Get all annotated class fields */ for (Field field : formFields) { FormElement annotation = field.getAnnotation(FormElement.class); String sectionTitle = annotation.section() == android.R.string.untitled ? "" : getContext().getString(annotation.section()); Section section = null; for (Section iterateSection : sections) { if (iterateSection.title == sectionTitle) { section = iterateSection; } } if (section == null) { section = new Section(sectionTitle); sections.add(section); } if (!section.multiValue) { section.multiValue = annotation.multiValue(); } section.fields.add(field); } /** * Sort fields by sortId - annotation property */ for (Section section : sections) { List<Field> sectionFields = section.fields; SectionDescriptor sectionDescriptor = SectionDescriptor.newInstance(section.tag, section.title); sectionDescriptor.setMultivalueSection(section.multiValue); for (Field field : sectionFields) { FormElement annotation = field.getAnnotation(FormElement.class); if (annotation != null) { Value<Object> value = null; try { value = new Value<Object>(field.get(object)); } catch (IllegalAccessException e) { Log.e(TAG, e.getMessage(), e); } if (section.multiValue) { sectionDescriptor.setTag(field.getName()); int index = 0; if ((value != null ? value.getValue() : null) instanceof ArrayList) { @SuppressWarnings("unchecked") ArrayList<Object> list = (ArrayList<Object>) value.getValue(); for (Object item : list) { RowDescriptor rowDescriptor = RowDescriptor.newInstance(annotation.tag().length() > 0 ? annotation.tag() : field.getName() + index, annotation.rowDescriptorType()); rowDescriptor.setValue(new Value<Object>(item)); rowDescriptor.setHint(annotation.hint()); sectionDescriptor.addRow(rowDescriptor, cellConfig); index++; } } RowDescriptor rowDescriptor = RowDescriptor.newInstance(annotation.tag().length() > 0 ? annotation.tag() : field.getName() + ++index, annotation.rowDescriptorType()); rowDescriptor.setHint(annotation.hint()); addValidators(rowDescriptor, annotation); sectionDescriptor.addRow(rowDescriptor, cellConfig); } else { RowDescriptor rowDescriptor = RowDescriptor.newInstance(annotation.tag().length() > 0 ? annotation.tag() : field.getName(), annotation.rowDescriptorType(), getContext().getString(annotation.label()), value); rowDescriptor.setHint(annotation.hint()); rowDescriptor.setRequired(annotation.required()); rowDescriptor.setDisabled(annotation.disabled()); rowDescriptor.setSelectorOptions(convertFormOptionsAnnotation( annotation.selectorOptions())); addValidators(rowDescriptor, annotation); boolean shouldAdd = true; if (object instanceof FormElementDelegate) { FormElementDelegate delegate = (FormElementDelegate) object; shouldAdd = delegate.shouldAddRowDescriptorForField(rowDescriptor, field); } if (shouldAdd) { sectionDescriptor.addRow(rowDescriptor, cellConfig); } } } } if (sectionDescriptor.getRowCount()>0){ formDescriptor.addSection(sectionDescriptor); } } return formDescriptor; } public void addValidators(RowDescriptor rowDescriptor, FormElement annotation) { for (Class validator : annotation.validatorClasses()) { try { rowDescriptor.addValidator((FormValidator) validator.getConstructor().newInstance()); } catch (InstantiationException e) { Log.e(TAG, e.getMessage(), e); } catch (IllegalAccessException e) { Log.e(TAG, e.getMessage(), e); } catch (InvocationTargetException e) { Log.e(TAG, e.getMessage(), e); } catch (NoSuchMethodException e) { Log.e(TAG, e.getMessage(), e); } catch (ClassCastException e) { Log.e(TAG, e.getMessage(), e); } } } public static ArrayList<FormOptionsObject> convertFormOptionsAnnotation(FormOptionsObjectElement[] options) { ArrayList<FormOptionsObject> optionsArrayList = new ArrayList<FormOptionsObject>(); for (FormOptionsObjectElement option : options) { if (option.valueType() == FormOptionsObjectElement.ValueTypes.INT) { optionsArrayList.add(FormOptionsObject.createFormOptionsObject(Integer.valueOf(option.value()), option.displayText())); } else if (option.valueType() == FormOptionsObjectElement.ValueTypes.DOUBLE) { optionsArrayList.add(FormOptionsObject.createFormOptionsObject(Double.valueOf(option.value()), option.displayText())); } else { optionsArrayList.add(FormOptionsObject.createFormOptionsObject(option.value(), option.displayText())); } } return optionsArrayList; } public List<Field> getAllFields(List<Field> fields, Class<?> type) { for (Field field : type.getDeclaredFields()) { fields.add(field); } if (type.getSuperclass() != null) { fields = getAllFields(fields, type.getSuperclass()); } return fields; } private String toCamelCase(String s) { String[] parts = s.split("_"); String camelCaseString = ""; for (String part : parts) { camelCaseString = camelCaseString + toProperCase(part); } return camelCaseString; } private String toProperCase(String s) { return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase(); } private class Section { private static final String DEFAULT_TITLE = ""; private static final String DEFAULT_TAG = ""; public String title; public String tag; public Boolean multiValue; public List<Field> fields; ; public Section(String sectionTitle) { title = DEFAULT_TITLE; tag = DEFAULT_TAG; multiValue = false; fields = new ArrayList<>(); if (sectionTitle != null && sectionTitle.length() > 0) { title = sectionTitle; tag = toCamelCase(sectionTitle); } } } }