1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.core.jpa.metadata;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.kuali.rice.core.jpa.annotations.Sequence;
20
21 import javax.persistence.*;
22 import java.lang.reflect.Field;
23 import java.lang.reflect.Modifier;
24 import java.lang.reflect.ParameterizedType;
25 import java.util.*;
26
27
28
29
30 public class MetadataManager {
31
32 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(MetadataManager.class);
33
34 private static Map<Class, EntityDescriptor> entitesByClass = Collections.synchronizedMap( new HashMap<Class, EntityDescriptor>() );
35 private static Map<String, EntityDescriptor> entitesByName = Collections.synchronizedMap( new HashMap<String, EntityDescriptor>() );
36
37 private MetadataManager() {}
38
39 public static EntityDescriptor getEntityDescriptor(Class clazz) {
40 if (clazz != null && clazz.getName().contains("$$EnhancerByCGLIB")) {
41 try {
42 clazz = Class.forName(clazz.getName().substring(0, clazz.getName().indexOf("$$EnhancerByCGLIB")));
43 } catch (Exception e) {
44 LOG.error(e.getMessage(), e);
45 }
46 }
47
48 EntityDescriptor entityDescriptor = addEntity(clazz);
49 return entityDescriptor;
50 }
51
52 public static Map<String, Object> getPersistableBusinessObjectPrimaryKeyValuePairs(Object object) {
53 Map<String, Object> pks = new HashMap<String, Object>();
54 EntityDescriptor descriptor = getEntityDescriptor(object.getClass());
55 for (FieldDescriptor fieldDescriptor : descriptor.getPrimaryKeys()) {
56 try {
57 Field field = getField(object.getClass(), fieldDescriptor.getName());
58 field.setAccessible(true);
59 pks.put(fieldDescriptor.getName(), field.get(object));
60 } catch (Exception e) {
61 LOG.error(e.getMessage(), e);
62 }
63 }
64 return pks;
65 }
66
67 private static Field getField(Class clazz, String name) throws NoSuchFieldException {
68 if (clazz.equals(Object.class)) {
69 throw new NoSuchFieldException(name);
70 }
71 Field field = null;
72 try {
73 field = clazz.getDeclaredField(name);
74 } catch (Exception e) {}
75 if (field == null) {
76 field = getField(clazz.getSuperclass(), name);
77 }
78 return field;
79 }
80
81 private static EntityDescriptor addEntity(Class clazz) {
82 EntityDescriptor entity = entitesByClass.get(clazz);
83 if (entity == null) {
84 entity = construct(clazz);
85 if (entity != null) {
86 entitesByClass.put(entity.getClazz(), entity);
87 entitesByName.put(entity.getName(), entity);
88 }
89 }
90 return entity;
91 }
92
93 @SuppressWarnings("unchecked")
94 private static EntityDescriptor construct(Class clazz) {
95 if (!clazz.isAnnotationPresent(Entity.class)) {
96 return null;
97 }
98
99
100 EntityDescriptor entityDescriptor = new EntityDescriptor();
101 entityDescriptor.setClazz(clazz);
102 String defaultName = clazz.getName().substring(clazz.getName().lastIndexOf(".") + 1);
103 Entity entity = (Entity) clazz.getAnnotation(Entity.class);
104 if (StringUtils.isBlank(entity.name())) {
105 entityDescriptor.setName(defaultName);
106 } else {
107 entityDescriptor.setName(entity.name());
108 }
109 if (clazz.isAnnotationPresent(Table.class)) {
110 Table table = (Table) clazz.getAnnotation(Table.class);
111 entityDescriptor.setTable(table.name());
112 } else {
113 entityDescriptor.setTable(defaultName);
114 }
115 if (clazz.isAnnotationPresent(IdClass.class)) {
116 entityDescriptor.setIdClass(clazz.getAnnotation(IdClass.class).getClass());
117 }
118 if (clazz.isAnnotationPresent(Sequence.class)) {
119 entityDescriptor.setSequence((Sequence)clazz.getAnnotation(Sequence.class));
120 }
121
122
123 try {
124 Class extensionClass = Class.forName(clazz.getName() + "Extension");
125 OneToOneDescriptor descriptor = new OneToOneDescriptor();
126 descriptor.setCascade(new CascadeType[] { CascadeType.PERSIST });
127 descriptor.setAttributeName("extension");
128 descriptor.setTargetEntity(extensionClass);
129 descriptor.setMappedBy("extension");
130 EntityDescriptor extensionDescriptor = MetadataManager.getEntityDescriptor(extensionClass);
131 for (FieldDescriptor fd : extensionDescriptor.getPrimaryKeys()) {
132 descriptor.addFkField(fd.getName());
133 }
134 entityDescriptor.add(descriptor);
135 FieldDescriptor extension = new FieldDescriptor();
136 extension.setName("extension");
137 extension.setClazz(extensionClass);
138 entityDescriptor.add(extension);
139 } catch (Exception e) {}
140
141
142 List<Class> classes = new ArrayList<Class>();
143 classes.add(clazz);
144 Class c = clazz;
145 while (!c.getSuperclass().equals(Object.class)) {
146 c = c.getSuperclass();
147 classes.add(c);
148 }
149 Collections.reverse(classes);
150
151
152 for (Class temp : classes) {
153 extractFieldMetadata(temp, entityDescriptor);
154 if (temp.isAnnotationPresent(AttributeOverrides.class)) {
155 for (AttributeOverride override : ((AttributeOverrides)temp.getAnnotation(AttributeOverrides.class)).value()) {
156 entityDescriptor.getFieldByName(override.name()).setColumn(override.column().name());
157 }
158 }
159 if (temp.isAnnotationPresent(AttributeOverride.class)) {
160 AttributeOverride override = (AttributeOverride) temp.getAnnotation(AttributeOverride.class);
161 entityDescriptor.getFieldByName(override.name()).setColumn(override.column().name());
162 }
163 }
164
165 return entityDescriptor;
166 }
167
168 private static void extractFieldMetadata(Class clazz, EntityDescriptor entityDescriptor) {
169
170 Set<String> cachedFields = new HashSet<String>();
171 do {
172 for (Field field : clazz.getDeclaredFields()) {
173 if (cachedFields.contains(field.getName())) {
174 continue;
175 }
176 cachedFields.add(field.getName());
177
178 int mods = field.getModifiers();
179 if (Modifier.isFinal(mods) || Modifier.isStatic(mods) || Modifier.isTransient(mods) || field.isAnnotationPresent(Transient.class)) {
180 continue;
181 }
182
183
184 FieldDescriptor fieldDescriptor = new FieldDescriptor();
185 fieldDescriptor.setClazz(field.getType());
186 fieldDescriptor.setName(field.getName());
187 if (field.isAnnotationPresent(Id.class)) {
188 fieldDescriptor.setId(true);
189 }
190 if (field.isAnnotationPresent(Column.class)) {
191 Column column = field.getAnnotation(Column.class);
192 fieldDescriptor.setColumn(column.name());
193 fieldDescriptor.setInsertable(column.insertable());
194 fieldDescriptor.setLength(column.length());
195 fieldDescriptor.setNullable(column.nullable());
196 fieldDescriptor.setPrecision(column.precision());
197 fieldDescriptor.setScale(column.scale());
198 fieldDescriptor.setUnique(column.unique());
199 fieldDescriptor.setUpdateable(column.updatable());
200 } else {
201 fieldDescriptor.setColumn(field.getName());
202 }
203 if (field.isAnnotationPresent(Version.class)) {
204 fieldDescriptor.setVersion(true);
205 }
206 if (field.isAnnotationPresent(Lob.class)) {
207 fieldDescriptor.setLob(true);
208 }
209 if (field.isAnnotationPresent(Temporal.class)) {
210 fieldDescriptor.setTemporal(true);
211 fieldDescriptor.setTemporalType(field.getAnnotation(Temporal.class).value());
212 }
213
214
215 if (field.isAnnotationPresent(OneToOne.class)) {
216 OneToOneDescriptor descriptor = new OneToOneDescriptor();
217 OneToOne relation = field.getAnnotation(OneToOne.class);
218 descriptor.setAttributeName(field.getName());
219 if (relation.targetEntity().equals(void.class)) {
220 descriptor.setTargetEntity(field.getType());
221 } else {
222 descriptor.setTargetEntity(relation.targetEntity());
223 }
224 descriptor.setCascade(relation.cascade());
225 descriptor.setFetch(relation.fetch());
226 descriptor.setMappedBy(relation.mappedBy());
227 descriptor.setOptional(relation.optional());
228 if (field.isAnnotationPresent(JoinColumn.class)) {
229 JoinColumn jc = field.getAnnotation(JoinColumn.class);
230 descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
231 descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
232 descriptor.setInsertable(jc.insertable());
233 descriptor.setUpdateable(jc.updatable());
234 }
235 if (field.isAnnotationPresent(JoinColumns.class)) {
236 JoinColumns jcs = field.getAnnotation(JoinColumns.class);
237 for (JoinColumn jc : jcs.value()) {
238 descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
239 descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
240 descriptor.setInsertable(jc.insertable());
241 descriptor.setUpdateable(jc.updatable());
242 }
243 }
244 entityDescriptor.add(descriptor);
245 }
246
247 if (field.isAnnotationPresent(OneToMany.class)) {
248 OneToManyDescriptor descriptor = new OneToManyDescriptor();
249 OneToMany relation = field.getAnnotation(OneToMany.class);
250 descriptor.setAttributeName(field.getName());
251 if (relation.targetEntity().equals(void.class)) {
252 descriptor.setTargetEntity((Class)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]);
253 } else {
254 descriptor.setTargetEntity(relation.targetEntity());
255 }
256 descriptor.setCascade(relation.cascade());
257 descriptor.setFetch(relation.fetch());
258 descriptor.setMappedBy(relation.mappedBy());
259 EntityDescriptor mappedBy = MetadataManager.getEntityDescriptor(descriptor.getTargetEntity());
260 ObjectDescriptor od = mappedBy.getObjectDescriptorByName(descriptor.getMappedBy());
261 if (od != null) {
262 for (String fk : od.getForeignKeyFields()) {
263 descriptor.addFkField(fk);
264 }
265 }
266 if (field.isAnnotationPresent(JoinTable.class)) {
267 JoinTable jt = field.getAnnotation(JoinTable.class);
268 for (JoinColumn jc : jt.joinColumns()) {
269 descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
270 descriptor.setInsertable(jc.insertable());
271 descriptor.setUpdateable(jc.updatable());
272 }
273 for (JoinColumn jc : jt.inverseJoinColumns()) {
274 descriptor.setInsertable(jc.insertable());
275 descriptor.setUpdateable(jc.updatable());
276
277 }
278 }
279 entityDescriptor.add(descriptor);
280 }
281
282 if (field.isAnnotationPresent(ManyToOne.class)) {
283 ManyToOne relation = field.getAnnotation(ManyToOne.class);
284 ManyToOneDescriptor descriptor = new ManyToOneDescriptor();
285 descriptor.setAttributeName(field.getName());
286 if (relation.targetEntity().equals(void.class)) {
287 descriptor.setTargetEntity(field.getType());
288 } else {
289 descriptor.setTargetEntity(relation.targetEntity());
290 }
291 descriptor.setCascade(relation.cascade());
292 descriptor.setFetch(relation.fetch());
293 descriptor.setOptional(relation.optional());
294 if (field.isAnnotationPresent(JoinColumn.class)) {
295 JoinColumn jc = field.getAnnotation(JoinColumn.class);
296 descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
297 descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
298 descriptor.setInsertable(jc.insertable());
299 descriptor.setUpdateable(jc.updatable());
300 }
301 if (field.isAnnotationPresent(JoinColumns.class)) {
302 JoinColumns jcs = field.getAnnotation(JoinColumns.class);
303 for (JoinColumn jc : jcs.value()) {
304 descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
305 descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
306 descriptor.setInsertable(jc.insertable());
307 descriptor.setUpdateable(jc.updatable());
308 }
309 }
310 entityDescriptor.add(descriptor);
311 }
312
313 if (field.isAnnotationPresent(ManyToMany.class)) {
314 ManyToManyDescriptor descriptor = new ManyToManyDescriptor();
315 ManyToMany relation = field.getAnnotation(ManyToMany.class);
316 descriptor.setAttributeName(field.getName());
317 if (relation.targetEntity().equals(void.class)) {
318 descriptor.setTargetEntity((Class)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]);
319 } else {
320 descriptor.setTargetEntity(relation.targetEntity());
321 }
322 descriptor.setCascade(relation.cascade());
323 descriptor.setFetch(relation.fetch());
324 descriptor.setMappedBy(relation.mappedBy());
325 if (field.isAnnotationPresent(JoinTable.class)) {
326 JoinTable jt = field.getAnnotation(JoinTable.class);
327 descriptor.setJoinTableName(jt.name());
328 for (JoinColumn jc : jt.joinColumns()) {
329 descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
330 descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
331 descriptor.setInsertable(jc.insertable());
332 descriptor.setUpdateable(jc.updatable());
333 }
334 for (JoinColumn jc : jt.inverseJoinColumns()) {
335 descriptor.addInverseJoinColumnDescriptor(constructJoinDescriptor(jc));
336 descriptor.setInsertable(jc.insertable());
337 descriptor.setUpdateable(jc.updatable());
338
339 }
340 }
341 entityDescriptor.add(descriptor);
342 }
343
344
345 entityDescriptor.add(fieldDescriptor);
346 }
347 clazz = clazz.getSuperclass();
348 } while (clazz != null && !(clazz.equals(Object.class)));
349 }
350
351 private static JoinColumnDescriptor constructJoinDescriptor(JoinColumn jc) {
352 JoinColumnDescriptor join = new JoinColumnDescriptor();
353 if (StringUtils.isBlank(jc.name())) {
354
355
356 throw new RuntimeException("Default name for Join Column not yet implemented!");
357 } else {
358 join.setName(jc.name());
359 }
360 join.setInsertable(jc.insertable());
361 join.setNullable(jc.nullable());
362 join.setUnique(jc.unique());
363 join.setUpdateable(jc.updatable());
364 return join;
365 }
366
367 }