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