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 }