Coverage Report - org.kuali.student.core.assembly.transform.DefaultDataBeanMapper
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultDataBeanMapper
78%
118/150
60%
82/136
9.125
 
 1  
 package org.kuali.student.core.assembly.transform;
 2  
 
 3  
 import java.beans.BeanInfo;
 4  
 import java.beans.Introspector;
 5  
 import java.beans.PropertyDescriptor;
 6  
 import java.lang.reflect.Field;
 7  
 import java.lang.reflect.ParameterizedType;
 8  
 import java.lang.reflect.Type;
 9  
 import java.sql.Time;
 10  
 import java.sql.Timestamp;
 11  
 import java.util.ArrayList;
 12  
 import java.util.Collection;
 13  
 import java.util.Date;
 14  
 import java.util.HashMap;
 15  
 import java.util.HashSet;
 16  
 import java.util.Iterator;
 17  
 import java.util.List;
 18  
 import java.util.Map;
 19  
 import java.util.Set;
 20  
 import java.util.Map.Entry;
 21  
 
 22  
 import org.kuali.student.core.assembly.data.Data;
 23  
 import org.kuali.student.core.assembly.data.Metadata;
 24  
 import org.kuali.student.core.assembly.data.Data.DataType;
 25  
 import org.kuali.student.core.assembly.data.Data.Key;
 26  
 import org.kuali.student.core.assembly.data.Data.Property;
 27  
 import org.kuali.student.core.assembly.data.Data.StringKey;
 28  
 
 29  
 
 30  2
 public class DefaultDataBeanMapper implements DataBeanMapper {
 31  1
         public static DataBeanMapper INSTANCE = new DefaultDataBeanMapper();
 32  
         
 33  
         /* (non-Javadoc)
 34  
          * @see org.kuali.student.core.assembly.data.DataBeanMapper#convertFromBean(java.lang.Object)
 35  
          */
 36  
         public Data convertFromBean(Object value) throws Exception{
 37  2
                  Data result = new Data();
 38  
                 
 39  2
                 if (value != null) {
 40  2
                 BeanInfo info = Introspector.getBeanInfo(value.getClass());
 41  2
                 PropertyDescriptor[] properties = info.getPropertyDescriptors();
 42  
                  
 43  24
                 for (PropertyDescriptor pd : properties) {
 44  22
                     String propKey = pd.getName();
 45  22
                     Object propValue = pd.getReadMethod().invoke(value, (Object[]) null);
 46  
                     
 47  22
                     if ("attributes".equals(propKey)){
 48  1
                             setDataAttributes(result, propValue);
 49  
                     } else {
 50  21
                             setDataValue(result, propKey, propValue);
 51  
                     }
 52  
                 }
 53  
                 }        
 54  
                 
 55  2
                 return result;
 56  
         }
 57  
         
 58  
         /* (non-Javadoc)
 59  
          * @see org.kuali.student.core.assembly.data.DataBeanMapper#convertFromData(org.kuali.student.core.assembly.data.Data, java.lang.Class)
 60  
          */
 61  
         public Object convertFromData(Data data, Class<?> clazz, Metadata metadata) throws Exception{
 62  2
                 Object result = null;
 63  
                 
 64  2
                 result = clazz.newInstance();
 65  2
         BeanInfo info = Introspector.getBeanInfo(result.getClass());
 66  2
         PropertyDescriptor[] properties = info.getPropertyDescriptors();
 67  
 
 68  2
         PropertyDescriptor attrProperty = null;
 69  
         
 70  2
         Set<Key> staticProperties = new HashSet<Key>();
 71  24
                 for (PropertyDescriptor pd : properties) {
 72  22
                         if ("attributes".equals(pd.getName())){
 73  
                                 //Dynamic attributes will be handled later
 74  1
                                 attrProperty = pd;
 75  
                         } else {
 76  21
                     StringKey propKey = new StringKey(pd.getName());
 77  21
                     Object propValue = data.get(propKey);
 78  
         
 79  
                     //Process a nested object structure or list
 80  21
                     if (propValue instanceof Data){
 81  1
                             clazz.getFields();
 82  1
                             if(metadata!=null){
 83  1
                                     if(DataType.LIST.equals(metadata.getDataType())){
 84  0
                                             propValue = convertNestedData((Data)propValue, clazz.getDeclaredField(propKey.toString()),metadata.getProperties().get("*"));
 85  
                                     }else{
 86  1
                                             propValue = convertNestedData((Data)propValue, clazz.getDeclaredField(propKey.toString()),metadata.getProperties().get(propKey.toString()));
 87  
                                     }
 88  
                             }
 89  
                             else{
 90  0
                                     propValue = convertNestedData((Data)propValue, clazz.getDeclaredField(propKey.toString()),null);
 91  
                             }
 92  20
                     }else if(metadata!=null&&propValue==null){
 93  1
                             Metadata fieldMetadata = metadata.getProperties().get(propKey.toString());
 94  1
                             if(fieldMetadata != null && fieldMetadata.getDefaultValue() != null){
 95  0
                                     propValue = fieldMetadata.getDefaultValue().get();        
 96  
                             }
 97  
                     }
 98  
                     
 99  
                             //Set the bean property
 100  21
                             if(pd.getWriteMethod() != null & propValue != null){    
 101  18
                         pd.getWriteMethod().invoke(result, new Object[] {propValue});
 102  
                     }
 103  
                     
 104  
                             //Hold onto the property so we know it is not dynamic
 105  21
                             staticProperties.add(propKey);
 106  
                         }
 107  
                 }
 108  
                 
 109  
                 //Any fields not processed above doesn't exist as properties for the bean and 
 110  
                 //will be set as dynamic attributes.
 111  2
                 Set<Key> keySet = data.keySet();
 112  2
                 if (keySet != null && attrProperty != null){
 113  1
                         Map<String,String> attributes = new HashMap<String,String>();
 114  1
             for (Key k : keySet) {
 115  11
                                 String keyString = k.toString();
 116  
                                 //Obtain the dynamic flag from the dictionary
 117  11
                                 if(metadata==null){
 118  11
                                         if (!staticProperties.contains(k) && data.get(k) != null && !keyString.startsWith("_run")){
 119  2
                                                 attributes.put((String)k.get(),data.get(k).toString());
 120  
                                         }
 121  
                                 }
 122  
                                 else {
 123  0
                                     if ((! staticProperties.contains(k)) &&
 124  
                                         (null != data.get(k)) &&
 125  
                                         (! keyString.startsWith("_run")) &&
 126  
                                         (null != metadata.getProperties().get(keyString)) &&
 127  
                                         (metadata.getProperties().get(keyString).isDynamic()))
 128  
                                     {
 129  0
                         attributes.put((String) k.get(), data.get(k).toString());
 130  
                                         }
 131  
                                 }
 132  11
                         }
 133  1
             if (attrProperty.getWriteMethod() != null) {
 134  1
                 attrProperty.getWriteMethod().invoke(result, new Object[] {attributes});
 135  
             }
 136  
                 }
 137  
 
 138  2
                 return result;
 139  
         }
 140  
         
 141  
         
 142  
         /**
 143  
          * Processes a nested data map, it checks to see if the data should be converted to 
 144  
          * a list structure or simply be processed as a nested complex object structure.
 145  
          * 
 146  
          * @param data
 147  
          * @param propField
 148  
          * @return
 149  
          * @throws Exception
 150  
          */
 151  
         protected Object convertNestedData(Data data, Field propField, Metadata metadata) throws Exception{
 152  1
                 Object result = null;
 153  
 
 154  1
                 Class<?> propClass = propField.getType();
 155  1
                 if ("java.util.List".equals(propClass.getName())){
 156  
                         //Get the generic type for the list
 157  1
                         ParameterizedType propType = (ParameterizedType)propField.getGenericType();
 158  1
                         Type itemType = propType.getActualTypeArguments()[0];
 159  
                         
 160  
                         
 161  1
                         List<Object> resultList = new ArrayList<Object>();
 162  1
                         for(Iterator<Property> listIter = data.realPropertyIterator(); listIter.hasNext();){
 163  1
                                 Property listItem = listIter.next();
 164  1
                                 Object listItemValue = listItem.getValue();
 165  1
                                 if (listItemValue instanceof Data ){
 166  1
                                         Data listItemData = (Data)listItemValue;
 167  1
                                         Boolean isDeleted = listItemData.query("_runtimeData/deleted");
 168  1
                                         if (isDeleted == null || !isDeleted){
 169  1
                                                 if(metadata!=null){
 170  0
                                                         listItemValue = convertFromData((Data)listItemValue, (Class<?>)itemType, metadata.getProperties().get("*"));
 171  
                                                 }else{
 172  1
                                                         listItemValue = convertFromData((Data)listItemValue, (Class<?>)itemType, null);
 173  
                                                 }
 174  1
                                                 resultList.add(listItemValue);
 175  
                                         }
 176  1
                                 } else {
 177  0
                                         resultList.add(listItemValue);
 178  
                                 }
 179  1
                         }
 180  
 
 181  1
                         result = resultList;
 182  1
                 } else {
 183  0
                         result = convertFromData(data, propClass,metadata);
 184  
                 }
 185  
                 
 186  1
                 return result;
 187  
         }
 188  
         
 189  
         /**
 190  
          * Used to set a simple property value into the data object. 
 191  
          * @param data
 192  
          * @param propertyKey
 193  
          * @param value
 194  
          * 
 195  
          */
 196  
         protected void setDataValue(Data data, String propertyKey, Object value) throws Exception{
 197  21
                 if (isPropertyValid(value)){
 198  18
                         if (value instanceof Boolean){
 199  0
                                 data.set(propertyKey, (Boolean)value);
 200  18
                         } else if (value instanceof Date){
 201  1
                                 data.set(propertyKey, (Date)value);
 202  17
                         } else if (value instanceof Integer){
 203  0
                                 data.set(propertyKey, (Integer)value);
 204  17
                         } else if (value instanceof Double){
 205  1
                                 data.set(propertyKey, (Double)value);
 206  16
                         } else if (value instanceof Float){
 207  0
                                 data.set(propertyKey, (Float)value);
 208  16
                         } else if (value instanceof Long) {
 209  0
                                 data.set(propertyKey, (Long)value);
 210  16
                         } else if (value instanceof Short){
 211  0
                                 data.set(propertyKey, (Short)value);                        
 212  16
                         } else if (value instanceof String){
 213  15
                                 data.set(propertyKey, (String)value);
 214  1
                         } else if (value instanceof Timestamp){
 215  0
                                 data.set(propertyKey, (Timestamp)value);
 216  1
                         } else if (value instanceof Time){
 217  0
                                 data.set(propertyKey, (Time)value);
 218  1
                         } else if (value instanceof Collection){
 219  1
                                 data.set(propertyKey, getCollectionData(value));
 220  
                         } else {
 221  0
                                 Data dataValue = convertFromBean(value);
 222  0
                                 data.set(propertyKey, dataValue);
 223  
                         }
 224  
                 }
 225  
                 
 226  21
         }
 227  
         
 228  
         /**
 229  
          * This process the attributes map and sets the attribute key/value pairs into the Data map
 230  
          * 
 231  
          * @param data
 232  
          * @param value
 233  
          */
 234  
         protected void setDataAttributes(Data data, Object value) {
 235  
                 @SuppressWarnings("unchecked")
 236  1
                 Map<String, String> attributes = (Map<String, String>)value;
 237  
                 
 238  1
                 for (Entry<String, String> entry:attributes.entrySet()){
 239  2
                         if("false".equals(entry.getValue())||"true".equals(entry.getValue())){
 240  0
                                 data.set(entry.getKey(), Boolean.valueOf(entry.getValue()));
 241  
                         }else{
 242  2
                                 data.set(entry.getKey(), entry.getValue());
 243  
                         }
 244  
                 }
 245  1
         }
 246  
 
 247  
         /**
 248  
          * Used to set a list item value into the data object.
 249  
          * 
 250  
          * @param data
 251  
          * @param value
 252  
          */
 253  
         protected void setDataListValue(Data data, Object value) throws Exception{
 254  1
                 if (isPropertyValid(value)){
 255  1
                         if (value instanceof Boolean){
 256  0
                                 data.add((Boolean)value);
 257  1
                         } else if (value instanceof Date){
 258  0
                                 data.add((Date)value);
 259  1
                         } else if (value instanceof Integer){
 260  0
                                 data.add((Integer)value);
 261  1
                         } else if (value instanceof Double){
 262  0
                                 data.add((Double)value);
 263  1
                         } else if (value instanceof Float){
 264  0
                                 data.add((Float)value);
 265  1
                         } else if (value instanceof Long) {
 266  0
                                 data.add((Long)value);
 267  1
                         } else if (value instanceof Short){
 268  0
                                 data.add((Short)value);                        
 269  1
                         } else if (value instanceof String){
 270  0
                                 data.add((String)value);
 271  1
                         } else if (value instanceof Timestamp){
 272  0
                                 data.add((Timestamp)value);
 273  1
                         } else if (value instanceof Time){
 274  0
                                 data.add((Time)value);
 275  1
                         } else if (value instanceof Collection){
 276  0
                                 data.add(getCollectionData(value));
 277  
                         } else {
 278  1
                                 Data dataValue = convertFromBean(value);
 279  1
                                 data.add(dataValue);                        
 280  
                         }
 281  
                 }
 282  1
         }
 283  
         
 284  
         /**
 285  
          * Returns a data map object representing a collection
 286  
          * 
 287  
          * @param value
 288  
          * @return
 289  
          * @throws Exception
 290  
          */
 291  
         protected Data getCollectionData(Object value) throws Exception{
 292  1
                 Data result = new Data();
 293  
                 
 294  1
                 if (value instanceof List){
 295  1
                         List<?> valueList = (List<?>)value;
 296  2
                         for (int i=0;i<valueList.size();i++){
 297  1
                                 Object itemValue = valueList.get(i); 
 298  1
                                 setDataListValue(result, itemValue);
 299  
                         }
 300  1
                 } else {
 301  0
                         Collection<?> valueCollection = (Collection<?>)value;
 302  0
                         for (Object o:valueCollection){
 303  0
                                 setDataListValue(result, o);
 304  
                         }
 305  
                 }
 306  
                 
 307  1
                 return result;
 308  
         }
 309  
         
 310  
         protected boolean isPropertyValid(Object value){
 311  22
                 boolean isValid = false;
 312  
                 
 313  22
                 if (value != null){
 314  21
                         Class<?> clazz = value.getClass();
 315  21
                         isValid = !(clazz.isArray() || clazz.isAnnotation() || value instanceof Class);
 316  
                 }
 317  
                 
 318  22
                 return isValid;
 319  
         }
 320  
 }