package org.springframework.data.simpledb.reflection; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Transient; import org.springframework.data.mapping.model.MappingException; import org.springframework.data.simpledb.annotation.Attributes; import org.springframework.stereotype.Component; @Component public final class MetadataParser { private static final Logger LOGGER = LoggerFactory.getLogger(MetadataParser.class); public static final String FIELD_NAME_DEFAULT_ID = "id"; private MetadataParser() { // Utility class } public static String getItemName(Object object) { Field idField = getIdField(object); if(idField != null) { try { idField.setAccessible(true); return (String) idField.get(object); } catch(IllegalAccessException e) { throw new MappingException("Could not read simpleDb id field", e); } } return null; } public static Field getIdField(Object object) { return getIdField(object.getClass()); } public static Field getIdField(Class<?> clazz) { Field idField = null; for(Field f : ReflectionUtils.getDeclaredFieldsInHierarchy(clazz)) { // named id or annotated with Id if(f.getName().equals(FIELD_NAME_DEFAULT_ID) || f.getAnnotation(Id.class) != null) { if(idField != null) { throw new MappingException("Multiple id fields detected for class " + clazz.getName()); } idField = f; } } return idField; } @SuppressWarnings("unchecked") public static Map<String, String> getAttributes(Object object) { Class<?> clazz = object.getClass(); for(Field f : clazz.getDeclaredFields()) { Attributes attributes = f.getAnnotation(Attributes.class); if(attributes != null) { try { f.setAccessible(true); return (Map<String, String>) f.get(object); } catch(IllegalAccessException e) { LOGGER.error("Could not read simpleDb attributes", e); } } } return null; } public static Field getAttributesField(Object object) { Class<?> clazz = object.getClass(); for(Field f : clazz.getDeclaredFields()) { // annotated with Attributes Attributes attributes = f.getAnnotation(Attributes.class); if(attributes != null) { return f; } } return null; } public static List<Field> getSupportedFields(Class<?> clazz) { List<Field> supportedFields = new ArrayList<Field>(); for(Field field : ReflectionUtils.getDeclaredFieldsInHierarchy(clazz)) { if(isSerializableFieldForObject(clazz, field)) { supportedFields.add(field); } } return supportedFields; } private static boolean isSerializableFieldForObject(Class<?> clazz, Field field) { boolean isSerializable = !hasUnsupportedAnnotations(field); isSerializable = isSerializable && !isTransientField(field); isSerializable = isSerializable && !(Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())); isSerializable = isSerializable && (ReflectionUtils.isPersistentField(field) || ReflectionUtils.hasDeclaredGetterAndSetter(field, clazz)); return isSerializable; } private static boolean hasUnsupportedAnnotations(Field field) { return (field.getAnnotation(Attributes.class) != null); } private static boolean isTransientField(Field field) { return field.isAnnotationPresent(Transient.class); } public static List<Field> getNestedDomainFields(Object object) { final List<Field> fieldList = new ArrayList<Field>(); for(Field field : object.getClass().getDeclaredFields()) { if(isNestedDomainField(field)) { fieldList.add(field); } } return fieldList; } public static boolean isNestedDomainField(Field field) { return FieldTypeIdentifier.isOfType(field, FieldType.NESTED_ENTITY); } public static void validateReferenceAnnotation(Field nestedField) { if(FieldType.REFERENCE_ENTITY.isOfType(nestedField) && getIdField(nestedField.getType()) != null) { return; } // TODO: check spring alliance - is converted to spring + make package for Reference Tests throw new IllegalStateException("Field @Reference " + nestedField.getName() + " should contain an @Id and should be a bean"); } }