1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  package org.kuali.student.datadictionary.util;
17  
18  import java.beans.BeanInfo;
19  import java.beans.IntrospectionException;
20  import java.beans.Introspector;
21  import java.beans.PropertyDescriptor;
22  import java.lang.reflect.Method;
23  import java.util.Date;
24  import java.util.List;
25  import java.util.Stack;
26  import org.kuali.rice.core.api.uif.DataType;
27  import org.kuali.rice.krad.datadictionary.AttributeDefinition;
28  import org.kuali.rice.krad.datadictionary.CollectionDefinition;
29  import org.kuali.rice.krad.datadictionary.ComplexAttributeDefinition;
30  import org.kuali.rice.krad.datadictionary.DataDictionaryDefinitionBase;
31  import org.kuali.rice.krad.datadictionary.DataObjectEntry;
32  
33  public class Bean2DictionaryConverter {
34  
35      private Class<?> clazz;
36      private Stack<DataDictionaryDefinitionBase> parentFields;
37      private Stack<Class<?>> parentClasses;
38  
39      public Bean2DictionaryConverter(Class<?> clazz, Stack<DataDictionaryDefinitionBase> parentFields, Stack<Class<?>> parentClasses) {
40          this.clazz = clazz;
41          this.parentFields = parentFields;
42          this.parentClasses = parentClasses;
43      }
44  
45      public DataObjectEntry convert() {
46          DataObjectEntry ode = new DataObjectEntry();
47          ode.setDataObjectClass(clazz);
48          addFields("", ode);
49          return ode;
50      }
51  
52      public void addFields(String debuggingContext, DataObjectEntry ode) {
53          BeanInfo beanInfo;
54          try {
55              beanInfo = Introspector.getBeanInfo(clazz);
56          } catch (IntrospectionException ex) {
57              throw new RuntimeException(ex);
58          }
59          for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
60              if (Class.class.equals(pd.getPropertyType())) {
61                  continue;
62              }
63              if ("_futureElements".equals(pd.getName())) {
64                  continue;
65              }
66              if ("attributes".equals(pd.getName())) {
67                  continue;
68              }
69              String name = calcName(pd.getName());
70              Class<?> actualClass = calcActualClass(clazz, pd);
71              DataType dt = calcDataType(debuggingContext + "." + clazz.getSimpleName() + "." + name, actualClass);
72              DataDictionaryDefinitionBase dddef = calcDataDictionaryDefinition(pd, dt);
73              if (dddef instanceof AttributeDefinition) {
74                  AttributeDefinition ad = (AttributeDefinition) dddef;
75                  ode.getAttributes().add(ad);
76              } else if (dddef instanceof ComplexAttributeDefinition) {
77                  ComplexAttributeDefinition cad = (ComplexAttributeDefinition) dddef;
78                  ode.getComplexAttributes().add(cad);
79                  if (!parentClasses.contains(clazz)) {
80                      parentFields.push(dddef);
81                      parentClasses.push(clazz);
82                      Bean2DictionaryConverter subConverter = new Bean2DictionaryConverter(actualClass, parentFields, parentClasses);
83                      subConverter.addFields(debuggingContext + "." + clazz.getSimpleName() + name, ode);
84                      parentFields.pop();
85                      parentClasses.pop();
86                  }
87              } else if (dddef instanceof CollectionDefinition) {
88                  CollectionDefinition cd = (CollectionDefinition) dddef;
89                  ode.getCollections().add(cd);
90                  
91                  
92  
93  
94  
95  
96  
97  
98  
99  
100 
101 
102 
103             }
104             if (dddef instanceof ComplexAttributeDefinition || dddef instanceof CollectionDefinition) {
105             }
106         }
107     }
108 
109     private DataDictionaryDefinitionBase calcDataDictionaryDefinition(PropertyDescriptor pd, DataType dataType) {
110         Class<?> pt = pd.getPropertyType();
111         if (List.class.equals(pt)) {
112             if (dataType != null) {
113                 System.out.println("WARNING: Can't handle lists of primitives just yet: " + calcName(pd.getName()));
114             }
115             CollectionDefinition cd = new CollectionDefinition();
116             cd.setName(calcName(pd.getName()));
117 
118             return cd;
119         }
120         if (dataType != null) {
121             AttributeDefinition ad = new AttributeDefinition();
122             ad.setName(calcName(pd.getName()));
123             ad.setDataType(dataType);
124             return ad;
125         }
126         ComplexAttributeDefinition cad = new ComplexAttributeDefinition();
127         cad.setName(calcName(pd.getName()));
128 
129         return cad;
130     }
131 
132     private String calcName(String leafName) {
133         StringBuilder bldr = new StringBuilder();
134         if (!parentFields.isEmpty()) {
135             DataDictionaryDefinitionBase parent = parentFields.peek();
136             if (parent instanceof ComplexAttributeDefinition) {
137                 ComplexAttributeDefinition cad = (ComplexAttributeDefinition) parent;
138                 bldr.append(cad.getName());
139                 bldr.append(".");
140             } else if (parent instanceof CollectionDefinition) {
141                 CollectionDefinition cad = (CollectionDefinition) parent;
142                 bldr.append(cad.getName());
143                 bldr.append(".");
144             }
145         }
146         bldr.append(initLower(leafName));
147         return bldr.toString();
148     }
149 
150     private String initLower(String name) {
151         return name.substring(0, 1).toLowerCase() + name.substring(1);
152     }
153 
154     public static Class<?> calcActualClass(Class<?> clazz, PropertyDescriptor pd) {
155         Class<?> pt = null;
156         
157         
158         
159         
160         
161         
162         
163         
164         
165         
166         
167         
168         pt = pd.getPropertyType();
169         if (pt.isInterface()) {
170             if (pd.getReadMethod() == null) {
171                 throw new NullPointerException (clazz.getName() + "." + pd.getName() + " has no read method");
172             }
173             pt = workAround(clazz, pd.getReadMethod().getName());
174         }
175         
176         if (List.class.equals(pt)) {
177             pt = ComplexSubstructuresHelper.getActualClassFromList(clazz, pd.getName());
178         }
179         return pt;
180     }
181 
182     private static Class<?> workAround(Class<?> currentTargetClass, String methodName) {
183         Method method = findMethodImplFirst(currentTargetClass, methodName);
184         return method.getReturnType();
185     }
186 
187     
188 
189 
190 
191 
192 
193 
194 
195 
196 
197 
198 
199     private static Method findMethodImplFirst(Class<?> currentTargetClass, String methodName, Class<?>... argTypes) {
200         Method method = null;
201         if (currentTargetClass != null && methodName != null) {
202             try {
203                 method = currentTargetClass.getMethod(methodName, argTypes);
204             } catch (Throwable t) {
205                 
206             }
207             
208             if (method == null) {
209                 Class<?> superclass = currentTargetClass.getSuperclass();
210                 if (!superclass.equals(Object.class)) {
211                     method = findMethodImplFirst(superclass, methodName, argTypes);
212                 }
213             }
214         }
215         return method;
216     }
217 
218     public static DataType calcDataType(String context, Class<?> pt) {
219         if (int.class.equals(pt) || Integer.class.equals(pt)) {
220             return DataType.INTEGER;
221         } else if (long.class.equals(pt) || Long.class.equals(pt)) {
222             return DataType.LONG;
223         } else if (double.class.equals(pt) || Double.class.equals(pt)) {
224             return DataType.DOUBLE;
225         } else if (float.class.equals(pt) || Float.class.equals(pt)) {
226             return DataType.FLOAT;
227         } else if (boolean.class.equals(pt) || Boolean.class.equals(pt)) {
228             return DataType.BOOLEAN;
229         } else if (Date.class.equals(pt)) {
230             return DataType.DATE;
231         } else if (String.class.equals(pt)) {
232             return DataType.STRING;
233         } else if (List.class.equals(pt)) {
234             throw new RuntimeException("Found list can't have a list of lists, List<List<?>> in " + context);
235         } else if (Enum.class.isAssignableFrom(pt)) {
236             return DataType.STRING;
237         } else if (Object.class.equals(pt)) {
238             return DataType.STRING;
239         } else if (pt.getName().startsWith("org.kuali.student.")) {
240             return null;
241         } else {
242             throw new RuntimeException("Found unknown/unhandled type of object in bean " + pt.getName() + " in " + context);
243         }
244     }
245 }