Coverage Report - org.kuali.rice.core.framework.persistence.jpa.metadata.MetadataManager
 
Classes in this File Line Coverage Branch Coverage Complexity
MetadataManager
0%
0/382
0%
0/182
11.25
 
 1  
 /*
 2  
  * Copyright 2007-2008 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.core.framework.persistence.jpa.metadata;
 17  
 
 18  
 import org.apache.commons.lang.StringUtils;
 19  
 import org.kuali.rice.core.framework.persistence.jpa.annotations.Sequence;
 20  
 
 21  
 import javax.persistence.AttributeOverride;
 22  
 import javax.persistence.AttributeOverrides;
 23  
 import javax.persistence.CascadeType;
 24  
 import javax.persistence.Column;
 25  
 import javax.persistence.Entity;
 26  
 import javax.persistence.Id;
 27  
 import javax.persistence.IdClass;
 28  
 import javax.persistence.JoinColumn;
 29  
 import javax.persistence.JoinColumns;
 30  
 import javax.persistence.JoinTable;
 31  
 import javax.persistence.Lob;
 32  
 import javax.persistence.ManyToMany;
 33  
 import javax.persistence.ManyToOne;
 34  
 import javax.persistence.OneToMany;
 35  
 import javax.persistence.OneToOne;
 36  
 import javax.persistence.Table;
 37  
 import javax.persistence.Temporal;
 38  
 import javax.persistence.Transient;
 39  
 import javax.persistence.Version;
 40  
 import java.lang.reflect.Field;
 41  
 import java.lang.reflect.Modifier;
 42  
 import java.lang.reflect.ParameterizedType;
 43  
 import java.util.ArrayList;
 44  
 import java.util.Collections;
 45  
 import java.util.HashMap;
 46  
 import java.util.HashSet;
 47  
 import java.util.List;
 48  
 import java.util.Map;
 49  
 import java.util.Set;
 50  
 
 51  
 /**
 52  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 53  
  */
 54  
 public class MetadataManager {
 55  
 
 56  0
         private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(MetadataManager.class);
 57  
         
 58  0
         private static Map<Class, EntityDescriptor> entitesByClass = Collections.synchronizedMap( new HashMap<Class, EntityDescriptor>() );
 59  0
         private static Map<String, EntityDescriptor> entitesByName = Collections.synchronizedMap( new HashMap<String, EntityDescriptor>() );
 60  
         
 61  0
         private MetadataManager() {}
 62  
 
 63  
         public static EntityDescriptor getEntityDescriptor(Class clazz) {
 64  0
                 if (clazz != null && clazz.getName().contains("$$EnhancerByCGLIB")) {
 65  
                         try {
 66  0
                                 clazz = Class.forName(clazz.getName().substring(0, clazz.getName().indexOf("$$EnhancerByCGLIB")));
 67  0
                         } catch (Exception e) {
 68  0
                                 LOG.error(e.getMessage(), e);
 69  0
                         }
 70  
                 }
 71  
 
 72  0
                 return addEntity(clazz);
 73  
         }
 74  
         
 75  
         public static Map<String, Object> getEntityPrimaryKeyValuePairs(Object object) {
 76  0
                 Map<String, Object> pks = new HashMap<String, Object>();
 77  0
                 EntityDescriptor descriptor = getEntityDescriptor(object.getClass());
 78  0
                 for (FieldDescriptor fieldDescriptor : descriptor.getPrimaryKeys()) {
 79  
                         try {
 80  0
                                 Field field = getField(object.getClass(), fieldDescriptor.getName());
 81  0
                                 field.setAccessible(true);
 82  0
                                 if (field.get(object) != null) {
 83  0
                                         pks.put(fieldDescriptor.getName(), field.get(object));
 84  
                                 }
 85  0
                         } catch (Exception e) {
 86  0
                                 LOG.error(e.getMessage(), e);
 87  0
                         }
 88  
                 }
 89  0
                 return pks;
 90  
         }
 91  
         
 92  
         /**
 93  
          * Retrieves the primary key as an object for the given Object (which is assumed to be a JPA entity).  If the entity has a single field
 94  
          * primary key, the value of that field is returned.  If a composite key is needed, it will be constructed and populated with the correct
 95  
          * values.  If a problem occurs, a null will be returned
 96  
          * 
 97  
          * @param object the object to get a primary key value from
 98  
          * @return a primary key value
 99  
          */
 100  
         public static Object getEntityPrimaryKeyObject(Object object) {
 101  0
                 final EntityDescriptor descriptor = getEntityDescriptor(object.getClass());
 102  0
                 final Class idClass = descriptor.getIdClass();
 103  0
                 if (idClass != null) {
 104  
                         try {
 105  0
                                 Object pkObject = idClass.newInstance();
 106  
                                 
 107  0
                                 for (FieldDescriptor fieldDescriptor : descriptor.getPrimaryKeys()) {
 108  0
                                         Field field = getField(object.getClass(), fieldDescriptor.getName());
 109  0
                                         field.setAccessible(true);
 110  0
                                         final Object value = field.get(object);
 111  0
                                         if (value != null) {
 112  0
                                                 final Field fieldToSet = getField(pkObject.getClass(), fieldDescriptor.getName());
 113  0
                                                 fieldToSet.setAccessible(true);
 114  0
                                                 fieldToSet.set(pkObject, value);
 115  
                                         }
 116  0
                                 }
 117  
                                 
 118  0
                                 return pkObject;
 119  0
                         } catch (SecurityException se) {
 120  0
                                 LOG.error(se.getMessage(), se);
 121  0
                         } catch (InstantiationException ie) {
 122  0
                                 LOG.error(ie.getMessage(), ie);
 123  0
                         } catch (IllegalAccessException iae) {
 124  0
                                 LOG.error(iae.getMessage(), iae);
 125  0
                         } catch (NoSuchFieldException nsfe) {
 126  0
                                 LOG.error(nsfe.getMessage(), nsfe);
 127  0
                         }
 128  
                 } else {
 129  0
                         for (FieldDescriptor fieldDescriptor : descriptor.getPrimaryKeys()) {
 130  
                                 try {
 131  0
                                         Field field = getField(object.getClass(), fieldDescriptor.getName());
 132  0
                                         field.setAccessible(true);
 133  0
                                         return field.get(object);  // there's only one value, let's kick out
 134  0
                                 } catch (Exception e) {
 135  0
                                         LOG.error(e.getMessage(), e);
 136  0
                                 }
 137  
                         }
 138  
                 }
 139  
                 
 140  0
                 return null;
 141  
         }
 142  
         
 143  
         /**
 144  
          * Retrieves the primary key as an object for the given Object (which is assumed to be a JPA entity), filling it with values from the extension.
 145  
          * If the entity has a single field primary key, the value of that field from the extension is returned.  If a composite key is needed, it will be 
 146  
          * constructed (based on the id class for the extension object) and populated with the correct values from the extension.  If a problem occurs, 
 147  
          * a null will be returned.
 148  
          * 
 149  
          * @param owner the object to get values from
 150  
          * @param extension the object to build a key for
 151  
          * @return a primary key value
 152  
          */
 153  
         public static Object getPersistableBusinessObjectPrimaryKeyObjectWithValuesForExtension(Object owner, Object extension) {
 154  0
                 final EntityDescriptor descriptor = getEntityDescriptor(extension.getClass());
 155  0
                 final Class idClass = descriptor.getIdClass();
 156  0
                 if (idClass != null) {
 157  
                         try {
 158  0
                                 Object pkObject = idClass.newInstance();
 159  
                                 
 160  0
                                 for (FieldDescriptor fieldDescriptor : descriptor.getPrimaryKeys()) {
 161  0
                                         Field field = getField(owner.getClass(), fieldDescriptor.getName());
 162  0
                                         field.setAccessible(true);
 163  0
                                         final Object value = field.get(owner);
 164  0
                                         if (value != null) {
 165  0
                                                 final Field fieldToSet = getField(pkObject.getClass(), fieldDescriptor.getName());
 166  0
                                                 fieldToSet.setAccessible(true);
 167  0
                                                 fieldToSet.set(pkObject, value);
 168  
                                         }
 169  0
                                 }
 170  
                                 
 171  0
                                 return pkObject;
 172  0
                         } catch (SecurityException se) {
 173  0
                                 LOG.error(se.getMessage(), se);
 174  0
                         } catch (InstantiationException ie) {
 175  0
                                 LOG.error(ie.getMessage(), ie);
 176  0
                         } catch (IllegalAccessException iae) {
 177  0
                                 LOG.error(iae.getMessage(), iae);
 178  0
                         } catch (NoSuchFieldException nsfe) {
 179  0
                                 LOG.error(nsfe.getMessage(), nsfe);
 180  0
                         }
 181  
                 } else {
 182  0
                         for (FieldDescriptor fieldDescriptor : descriptor.getPrimaryKeys()) {
 183  
                                 try {
 184  0
                                         Field field = getField(owner.getClass(), fieldDescriptor.getName());
 185  0
                                         field.setAccessible(true);
 186  0
                                         final Object value = field.get(owner);
 187  0
                                         return value;  // there's only one value, let's kick out
 188  0
                                 } catch (Exception e) {
 189  0
                                         LOG.error(e.getMessage(), e);
 190  0
                                 }
 191  
                         }
 192  
                 }
 193  
                 
 194  0
                 return null;
 195  
         }
 196  
         
 197  
         /**
 198  
          * This converts a map of primary keys into an object: in the case of a single key, just the value object iself; in the case of a composite key,
 199  
          * the correct composite key object populated with the values from the map
 200  
          * @param entityClazz the class of the entity the pkMap was for
 201  
          * @param pkMap the map of primary key fields and values
 202  
          * @return the correct primary key object
 203  
          */
 204  
         public static Object convertPrimaryKeyMapToObject(Class entityClazz, Map<String, Object> pkMap) {
 205  0
                 if (pkMap.isEmpty()) {
 206  0
                         return null;
 207  
                 }
 208  
                 
 209  0
                 final EntityDescriptor descriptor = getEntityDescriptor(entityClazz);
 210  0
                 final Class idClass = descriptor.getIdClass();
 211  
                 
 212  0
                 if (idClass == null) {
 213  0
                         if (pkMap.size() != 1) {
 214  0
                                 throw new IllegalArgumentException("pkMap has a size of "+pkMap.size()+"; but since entityClazz does not have a composite primary key, the size should be 1");
 215  
                         }
 216  0
                         for (String key : pkMap.keySet()) {
 217  0
                                 return pkMap.get(key);
 218  
                         }
 219  
                 } else {
 220  
                         try {
 221  0
                                 Object pkObject = idClass.newInstance();
 222  0
                                 for (String key : pkMap.keySet()) {
 223  0
                                         Field field = getField(idClass, key);
 224  0
                                         field.setAccessible(true);
 225  0
                                         field.set(pkObject, pkMap.get(key));
 226  0
                                 }
 227  0
                                 return pkObject;
 228  0
                         } catch (InstantiationException ie) {
 229  0
                                 throw new RuntimeException("Could not convert primary key map to composite key object", ie);
 230  0
                         } catch (IllegalAccessException iae) {
 231  0
                                 throw new RuntimeException("Could not convert primary key map to composite key object", iae);
 232  0
                         } catch (NoSuchFieldException nsfe) {
 233  0
                                 throw new RuntimeException("Could not convert primary key map to composite key object", nsfe);
 234  
                         }
 235  
                 }
 236  0
                 return null;// I don't believe this code is reachable, but...you never know
 237  
         }
 238  
         
 239  
         private static Field getField(Class clazz, String name) throws NoSuchFieldException {
 240  0
                 if (clazz.equals(Object.class)) {
 241  0
                         throw new NoSuchFieldException(name);
 242  
                 }
 243  0
                 Field field = null;
 244  
                 try {
 245  0
                         field = clazz.getDeclaredField(name);
 246  0
                 } catch (Exception e) {}
 247  0
                 if (field == null) {
 248  0
                         field = getField(clazz.getSuperclass(), name);
 249  
                 }
 250  0
                 return field;
 251  
         }
 252  
         
 253  
         private static EntityDescriptor addEntity(Class clazz) {
 254  0
                 EntityDescriptor entity = entitesByClass.get(clazz); 
 255  0
                 if (entity == null) {
 256  0
                         entity = construct(clazz);
 257  0
                         if (entity != null) {
 258  0
                                 entitesByClass.put(entity.getClazz(), entity);
 259  0
                                 entitesByName.put(entity.getName(), entity);
 260  
                         }
 261  
                 }
 262  0
                 return entity;
 263  
         }
 264  
 
 265  
         @SuppressWarnings("unchecked")
 266  
         private static EntityDescriptor construct(Class clazz) {
 267  0
                 if (!clazz.isAnnotationPresent(Entity.class)) {
 268  0
                         return null;
 269  
                 }
 270  
                 
 271  
                 // Determine the base entity metadata
 272  0
                 EntityDescriptor entityDescriptor = new EntityDescriptor();
 273  0
                 entityDescriptor.setClazz(clazz);
 274  0
                 String defaultName = clazz.getName().substring(clazz.getName().lastIndexOf(".") + 1);
 275  0
                 Entity entity = (Entity) clazz.getAnnotation(Entity.class);
 276  0
                 if (StringUtils.isBlank(entity.name())) {
 277  0
                         entityDescriptor.setName(defaultName);
 278  
                 } else {
 279  0
                         entityDescriptor.setName(entity.name());
 280  
                 }
 281  0
                 if (clazz.isAnnotationPresent(Table.class)) {
 282  0
                         Table table = (Table) clazz.getAnnotation(Table.class);
 283  0
                         entityDescriptor.setTable(table.name());
 284  0
                 } else {
 285  0
                         entityDescriptor.setTable(defaultName);
 286  
                 }
 287  0
                 if (clazz.isAnnotationPresent(IdClass.class)) {
 288  0
                         entityDescriptor.setIdClass(((IdClass)clazz.getAnnotation(IdClass.class)).value());
 289  
                 }
 290  0
                 if (clazz.isAnnotationPresent(Sequence.class)) {
 291  0
                         entityDescriptor.setSequence((Sequence)clazz.getAnnotation(Sequence.class));
 292  
                 }                
 293  
                 
 294  
                 // Check for an "extension"
 295  
                 try {
 296  0
                         Class extensionClass = Class.forName(clazz.getName() + "Extension");
 297  0
                         OneToOneDescriptor descriptor = new OneToOneDescriptor();
 298  0
                         descriptor.setCascade(new CascadeType[] { CascadeType.PERSIST });
 299  0
                         descriptor.setAttributeName("extension");
 300  0
                         descriptor.setTargetEntity(extensionClass);
 301  0
                         descriptor.setMappedBy("extension");
 302  0
                         EntityDescriptor extensionDescriptor = MetadataManager.getEntityDescriptor(extensionClass);
 303  0
                         for (FieldDescriptor fd : extensionDescriptor.getPrimaryKeys()) {
 304  0
                                 descriptor.addFkField(fd.getName());
 305  
                         }
 306  0
                         entityDescriptor.add(descriptor);
 307  0
                         FieldDescriptor extension = new FieldDescriptor();
 308  0
                         extension.setName("extension");
 309  0
                         extension.setClazz(extensionClass);
 310  0
                         entityDescriptor.add(extension);
 311  0
                 } catch (Exception e) {}
 312  
                 
 313  
                 
 314  0
                 List<Class> classes = new ArrayList<Class>();
 315  0
                 classes.add(clazz);
 316  0
                 Class c = clazz;
 317  0
                 while (!c.getSuperclass().equals(Object.class)) {
 318  0
                         c = c.getSuperclass();
 319  0
                         classes.add(c);
 320  
                 }
 321  0
                 Collections.reverse(classes);
 322  
                 
 323  
                 // Determine the field/relationship metadata for all classes in the clazz hierarchy
 324  0
                 for (Class temp : classes) {
 325  0
                         extractFieldMetadata(temp, entityDescriptor);
 326  0
                         if (temp.isAnnotationPresent(AttributeOverrides.class)) {
 327  0
                                 for (AttributeOverride override : ((AttributeOverrides)temp.getAnnotation(AttributeOverrides.class)).value()) {
 328  0
                                         entityDescriptor.getFieldByName(override.name()).setColumn(override.column().name());
 329  
                                 }
 330  
                         }
 331  0
                         if (temp.isAnnotationPresent(AttributeOverride.class)) {
 332  0
                                 AttributeOverride override = (AttributeOverride) temp.getAnnotation(AttributeOverride.class);
 333  0
                                 entityDescriptor.getFieldByName(override.name()).setColumn(override.column().name());                                        
 334  0
                         }
 335  
                         //if (temp.isAnnotationPresent(AssociationOverrides.class)) {
 336  
                         //        for (AssociationOverride override : ((AssociationOverrides)temp.getAnnotation(AssociationOverride.class)).value()) {
 337  
                         //                entityDescriptor.getFieldByName(override.name()).;
 338  
                         //        }
 339  
                         //}
 340  
                         //if (temp.isAnnotationPresent(AttributeOverride.class)) {
 341  
                         //        AttributeOverride override = (AttributeOverride) temp.getAnnotation(AttributeOverride.class);
 342  
                         //        entityDescriptor.getFieldByName(override.name()).setColumn(override.column().name());                                        
 343  
                         //}
 344  
                         
 345  
                 }
 346  
                                 
 347  0
                 return entityDescriptor;
 348  
         }
 349  
 
 350  
         
 351  
         private static void extractFieldMetadata(Class clazz, EntityDescriptor entityDescriptor) {
 352  
             // Don't want to get parent fields if overridden in children since we are walking the tree from child to parent
 353  0
                 Set<String> cachedFields = new HashSet<String>(); 
 354  
                 do {
 355  0
                         for (Field field : clazz.getDeclaredFields()) {
 356  0
                                 if (cachedFields.contains(field.getName())) {
 357  0
                                         continue;
 358  
                                 }
 359  0
                                 cachedFields.add(field.getName());
 360  
                                 
 361  0
                                 int mods = field.getModifiers();
 362  0
                                 if (Modifier.isFinal(mods) || Modifier.isStatic(mods) || Modifier.isTransient(mods) || field.isAnnotationPresent(Transient.class)) {
 363  0
                                         continue;
 364  
                                 }
 365  
 
 366  
                                 // Basic Fields
 367  0
                                 FieldDescriptor fieldDescriptor = new FieldDescriptor();
 368  0
                                 fieldDescriptor.setClazz(field.getType());
 369  0
                                 fieldDescriptor.setTargetClazz(field.getType());
 370  0
                                 fieldDescriptor.setName(field.getName());
 371  
                                 
 372  
                                 
 373  0
                                 if (field.isAnnotationPresent(Id.class)) {
 374  0
                                         fieldDescriptor.setId(true);
 375  
                                         
 376  0
                                         if (entityDescriptor.getIdClass() != null) {
 377  
                                                 // pull the column from IdClass
 378  
                                                 try {
 379  0
                                                         Field idClassField = entityDescriptor.getIdClass().getDeclaredField(field.getName());
 380  0
                                                         idClassField.setAccessible(true);
 381  0
                                                         addColumnInformationToFieldDescriptor(fieldDescriptor, idClassField);
 382  0
                                                 } catch (Exception e) {
 383  0
                                                         e.printStackTrace();
 384  0
                                                 }
 385  
                                         }
 386  
                                 }
 387  0
                                 if (field.isAnnotationPresent(Column.class)) {
 388  
                                         
 389  0
                                         if (!field.isAnnotationPresent(Id.class) || entityDescriptor.getIdClass() == null) {
 390  
                                                 // only populate if we haven't populated already
 391  0
                                                 addColumnInformationToFieldDescriptor(fieldDescriptor, field);
 392  
                                         }
 393  0
                                 } else if (!field.isAnnotationPresent(Id.class) || entityDescriptor.getIdClass() == null) {
 394  0
                                         fieldDescriptor.setColumn(field.getName());
 395  
                                 }
 396  0
                                 if (field.isAnnotationPresent(Version.class)) {
 397  0
                                         fieldDescriptor.setVersion(true);
 398  
                                 }
 399  0
                                 if (field.isAnnotationPresent(Lob.class)) {
 400  0
                                         fieldDescriptor.setLob(true);
 401  
                                 }
 402  0
                                 if (field.isAnnotationPresent(Temporal.class)) {
 403  0
                                         fieldDescriptor.setTemporal(true);
 404  0
                                         fieldDescriptor.setTemporalType(field.getAnnotation(Temporal.class).value());
 405  
                                 }                                
 406  
 
 407  
                                 
 408  
                                 // Relationships
 409  0
                                 if (field.isAnnotationPresent(OneToOne.class)) {
 410  0
                                         OneToOneDescriptor descriptor = new OneToOneDescriptor();
 411  0
                                         OneToOne relation = field.getAnnotation(OneToOne.class);
 412  0
                                         descriptor.setAttributeName(field.getName());
 413  0
                                         if (relation.targetEntity().equals(void.class)) {
 414  0
                                                 descriptor.setTargetEntity(field.getType());
 415  
                                         } else {
 416  0
                                                 descriptor.setTargetEntity(relation.targetEntity());
 417  0
                                                 fieldDescriptor.setTargetClazz(relation.targetEntity());
 418  
                                         }
 419  
                                         
 420  0
                                         descriptor.setCascade(relation.cascade());
 421  0
                                         descriptor.setFetch(relation.fetch());
 422  0
                                         descriptor.setMappedBy(relation.mappedBy());
 423  0
                                         descriptor.setOptional(relation.optional());
 424  0
                                         if (field.isAnnotationPresent(JoinColumn.class)) {
 425  0
                                                 JoinColumn jc = field.getAnnotation(JoinColumn.class);
 426  0
                                                 descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
 427  0
                                                 FieldDescriptor jcFkField = entityDescriptor.getFieldByColumnName(jc.name());
 428  0
                                                 if (jcFkField != null) {
 429  0
                                                         descriptor.addFkField(jcFkField.getName());
 430  
                                                 } else {
 431  
                                                         //check to see if foreign key is in an AttributeOverride annotation
 432  0
                                                         if (clazz.isAnnotationPresent(AttributeOverrides.class)) {
 433  0
                                                                 for (AttributeOverride override : ((AttributeOverrides)clazz.getAnnotation(AttributeOverrides.class)).value()) {
 434  0
                                                                         if (jc.name().equals(override.column().name())) {
 435  0
                                                                                 entityDescriptor.getFieldByName(override.name()).setColumn(override.column().name());
 436  0
                                                                                 jcFkField = entityDescriptor.getFieldByName(override.name());
 437  0
                                                                                 if (jcFkField != null) {
 438  0
                                                                                         descriptor.addFkField(jcFkField.getName());
 439  
                                                                                 }
 440  
                                                                         }
 441  
                                                                 }
 442  
                                                         }
 443  0
                                                         if (clazz.isAnnotationPresent(AttributeOverride.class)) {
 444  0
                                                                 AttributeOverride override = (AttributeOverride) clazz.getAnnotation(AttributeOverride.class);
 445  0
                                                                 if (jc.name().equals(override.column().name())) {
 446  0
                                                                         entityDescriptor.getFieldByName(override.name()).setColumn(override.column().name());
 447  0
                                                                         jcFkField = entityDescriptor.getFieldByName(override.name());
 448  0
                                                                         if (jcFkField != null) {
 449  0
                                                                                 descriptor.addFkField(jcFkField.getName());
 450  
                                                                         }
 451  
                                                                 }                                        
 452  
                                                         }
 453  
                                                 }
 454  
                                                 //descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
 455  0
                                                 descriptor.setInsertable(jc.insertable());
 456  0
                                                 descriptor.setUpdateable(jc.updatable());                                        
 457  
                                         }
 458  0
                                         if (field.isAnnotationPresent(JoinColumns.class)) {
 459  0
                                                 JoinColumns jcs = field.getAnnotation(JoinColumns.class);
 460  0
                                                 for (JoinColumn jc : jcs.value()) {
 461  0
                                                         descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
 462  0
                                                         descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
 463  0
                                                         descriptor.setInsertable(jc.insertable());
 464  0
                                                         descriptor.setUpdateable(jc.updatable());
 465  
                                                 } 
 466  
                                         }
 467  0
                                         entityDescriptor.add(descriptor);
 468  
                                 }
 469  
 
 470  0
                                 if (field.isAnnotationPresent(OneToMany.class)) {
 471  0
                                         OneToManyDescriptor descriptor = new OneToManyDescriptor();
 472  0
                                         OneToMany relation = field.getAnnotation(OneToMany.class);
 473  0
                                         descriptor.setAttributeName(field.getName());
 474  0
                                         if (relation.targetEntity().equals(void.class)) {
 475  0
                                                 descriptor.setTargetEntity((Class)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]);
 476  
                                         } else {
 477  0
                                                 descriptor.setTargetEntity(relation.targetEntity());
 478  0
                                                 fieldDescriptor.setTargetClazz(relation.targetEntity());
 479  
                                         }
 480  0
                                         descriptor.setCascade(relation.cascade());
 481  0
                                         descriptor.setFetch(relation.fetch());
 482  0
                                         descriptor.setMappedBy(relation.mappedBy());
 483  0
                                         EntityDescriptor mappedBy = (entityDescriptor.getClazz().equals(descriptor.getTargetEntity())) ?
 484  
                                                         entityDescriptor : MetadataManager.getEntityDescriptor(descriptor.getTargetEntity());
 485  0
                                         ObjectDescriptor od = mappedBy.getObjectDescriptorByName(descriptor.getMappedBy());
 486  0
                                         if (od != null) {
 487  0
                                                 for (String fk : od.getForeignKeyFields()) {                                
 488  0
                                                         descriptor.addFkField(fk);
 489  
                                                 }
 490  
                                         }
 491  0
                                         if (field.isAnnotationPresent(JoinTable.class)) {
 492  0
                                                 JoinTable jt = field.getAnnotation(JoinTable.class);
 493  0
                                                 for (JoinColumn jc : jt.joinColumns()) {
 494  0
                                                         descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
 495  0
                                                         descriptor.setInsertable(jc.insertable());
 496  0
                                                         descriptor.setUpdateable(jc.updatable());
 497  0
                                                         descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
 498  
                                                 } 
 499  0
                                                 for (JoinColumn jc : jt.inverseJoinColumns()) {
 500  0
                                                         descriptor.setInsertable(jc.insertable());
 501  0
                                                         descriptor.setUpdateable(jc.updatable());
 502  0
                                                         descriptor.addInverseJoinColumnDescriptor(constructJoinDescriptor(jc));
 503  
                                                 } 
 504  0
                                         } else {
 505  0
                                                 if (field.isAnnotationPresent(JoinColumn.class)) {
 506  0
                                                         JoinColumn jc = field.getAnnotation(JoinColumn.class);
 507  0
                                                         FieldDescriptor jcFkField = entityDescriptor.getFieldByColumnName(jc.name());
 508  0
                                                         if (jcFkField != null) {
 509  0
                                                                 descriptor.addFkField(jcFkField.getName());
 510  
                                                         }
 511  0
                                                         descriptor.setInsertable(jc.insertable());
 512  0
                                                         descriptor.setUpdateable(jc.updatable());
 513  0
                                                         descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
 514  
                                                 }
 515  0
                                                 if (field.isAnnotationPresent(JoinColumns.class)) {
 516  0
                                                         JoinColumns jcs = field.getAnnotation(JoinColumns.class);
 517  0
                                                         for (JoinColumn jc : jcs.value()) {
 518  0
                                                                 descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
 519  0
                                                                 descriptor.setInsertable(jc.insertable());
 520  0
                                                                 descriptor.setUpdateable(jc.updatable());
 521  0
                                                                 descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
 522  
                                                         } 
 523  
                                                 }
 524  
                                         }
 525  0
                                         entityDescriptor.add(descriptor);
 526  
                                 }
 527  
 
 528  0
                                 if (field.isAnnotationPresent(ManyToOne.class)) {
 529  0
                                         ManyToOne relation = field.getAnnotation(ManyToOne.class);
 530  0
                                         ManyToOneDescriptor descriptor = new ManyToOneDescriptor();
 531  0
                                         descriptor.setAttributeName(field.getName());
 532  0
                                         if (relation.targetEntity().equals(void.class)) {
 533  0
                                                 descriptor.setTargetEntity(field.getType());
 534  
                                         } else {
 535  0
                                                 descriptor.setTargetEntity(relation.targetEntity());
 536  0
                                                 fieldDescriptor.setTargetClazz(relation.targetEntity());
 537  
                                         }
 538  0
                                         descriptor.setCascade(relation.cascade());
 539  0
                                         descriptor.setFetch(relation.fetch());
 540  0
                                         descriptor.setOptional(relation.optional());
 541  0
                                         if (field.isAnnotationPresent(JoinColumn.class)) {
 542  0
                                                 JoinColumn jc = field.getAnnotation(JoinColumn.class);
 543  0
                                                 descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
 544  0
                                                 FieldDescriptor jcFkField = entityDescriptor.getFieldByColumnName(jc.name());
 545  0
                                                 if (jcFkField != null) {
 546  0
                                                         descriptor.addFkField(jcFkField.getName());
 547  
                                                 }
 548  
                                                 //descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
 549  
                                                 //descriptor.addFkField(entitesByClass.get(field.getType()).getFieldByColumnName(jc.name()).getName());
 550  0
                                                 descriptor.setInsertable(jc.insertable());
 551  0
                                                 descriptor.setUpdateable(jc.updatable());
 552  
                                         }
 553  0
                                         if (field.isAnnotationPresent(JoinColumns.class)) {
 554  0
                                                 JoinColumns jcs = field.getAnnotation(JoinColumns.class);
 555  0
                                                 for (JoinColumn jc : jcs.value()) {
 556  0
                                                         descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
 557  0
                                                         descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
 558  0
                                                         descriptor.setInsertable(jc.insertable());
 559  0
                                                         descriptor.setUpdateable(jc.updatable());
 560  
                                                 } 
 561  
                                         }
 562  0
                                         entityDescriptor.add(descriptor);
 563  
                                 }
 564  
 
 565  0
                                 if (field.isAnnotationPresent(ManyToMany.class)) {
 566  0
                                         ManyToManyDescriptor descriptor = new ManyToManyDescriptor();
 567  0
                                         ManyToMany relation = field.getAnnotation(ManyToMany.class);
 568  0
                                         descriptor.setAttributeName(field.getName());
 569  0
                                         if (relation.targetEntity().equals(void.class)) {
 570  0
                                                 descriptor.setTargetEntity((Class)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]);
 571  
                                         } else {
 572  0
                                                 descriptor.setTargetEntity(relation.targetEntity());
 573  0
                                                 fieldDescriptor.setTargetClazz(relation.targetEntity());
 574  
                                         }
 575  0
                                         descriptor.setCascade(relation.cascade());
 576  0
                                         descriptor.setFetch(relation.fetch());
 577  0
                                         descriptor.setMappedBy(relation.mappedBy());
 578  0
                                         if (field.isAnnotationPresent(JoinTable.class)) {
 579  0
                                                 JoinTable jt = field.getAnnotation(JoinTable.class);
 580  0
                                                 descriptor.setJoinTableName(jt.name());
 581  0
                                                 for (JoinColumn jc : jt.joinColumns()) {
 582  0
                                                         descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
 583  0
                                                         descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
 584  0
                                                         descriptor.setInsertable(jc.insertable());
 585  0
                                                         descriptor.setUpdateable(jc.updatable());
 586  
                                                 } 
 587  0
                                                 for (JoinColumn jc : jt.inverseJoinColumns()) {
 588  0
                                                         descriptor.addInverseJoinColumnDescriptor(constructJoinDescriptor(jc));
 589  0
                                                         descriptor.setInsertable(jc.insertable());
 590  0
                                                         descriptor.setUpdateable(jc.updatable());
 591  
                                                         // TODO: Should we add inverse join columns?
 592  
                                                 } 
 593  0
                                         } else {
 594  0
                                                 if (field.isAnnotationPresent(JoinColumn.class)) {
 595  0
                                                         JoinColumn jc = field.getAnnotation(JoinColumn.class);
 596  0
                                                         FieldDescriptor jcFkField = entityDescriptor.getFieldByColumnName(jc.name());
 597  0
                                                         if (jcFkField != null) {
 598  0
                                                                 descriptor.addFkField(jcFkField.getName());
 599  
                                                         }
 600  0
                                                         descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
 601  0
                                                         descriptor.setInsertable(jc.insertable());
 602  0
                                                         descriptor.setUpdateable(jc.updatable());
 603  
                                                 }
 604  0
                                                 if (field.isAnnotationPresent(JoinColumns.class)) {
 605  0
                                                         JoinColumns jcs = field.getAnnotation(JoinColumns.class);
 606  0
                                                         for (JoinColumn jc : jcs.value()) {
 607  0
                                                                 descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
 608  0
                                                                 descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
 609  0
                                                                 descriptor.setInsertable(jc.insertable());
 610  0
                                                                 descriptor.setUpdateable(jc.updatable());
 611  
                                                         } 
 612  
                                                 }
 613  
                                         }
 614  0
                                         entityDescriptor.add(descriptor);                                                
 615  
                                 }
 616  
 
 617  
                                 // Add the field to the entity
 618  0
                                 entityDescriptor.add(fieldDescriptor);
 619  
                         }
 620  0
                         clazz = clazz.getSuperclass();
 621  0
                 } while (clazz != null && !(clazz.equals(Object.class)));
 622  0
         }
 623  
         
 624  
         /**
 625  
          * Populate a FieldDescriptor with Column annotation information
 626  
          * 
 627  
          * @param fieldDescriptor the FieldDescriptor to populate
 628  
          * @param field the field which has the annotation
 629  
          */
 630  
         private static void addColumnInformationToFieldDescriptor(FieldDescriptor fieldDescriptor, Field field) {
 631  0
                 Column column = field.getAnnotation(Column.class);
 632  0
                 fieldDescriptor.setColumn(column.name());
 633  0
                 fieldDescriptor.setInsertable(column.insertable());
 634  0
                 fieldDescriptor.setLength(column.length());
 635  0
                 fieldDescriptor.setNullable(column.nullable());
 636  0
                 fieldDescriptor.setPrecision(column.precision());
 637  0
                 fieldDescriptor.setScale(column.scale());
 638  0
                 fieldDescriptor.setUnique(column.unique());
 639  0
                 fieldDescriptor.setUpdateable(column.updatable());
 640  0
         }
 641  
 
 642  
         private static JoinColumnDescriptor constructJoinDescriptor(JoinColumn jc) {
 643  0
                 JoinColumnDescriptor join = new JoinColumnDescriptor();
 644  0
                 if (StringUtils.isBlank(jc.name())) {
 645  
                         // TODO: Implement default name
 646  
                         // See: http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#JoinColumn
 647  0
                         throw new RuntimeException("Default name for Join Column not yet implemented!");
 648  
                 } else {
 649  0
                         join.setName(jc.name());
 650  
                 }
 651  0
                 join.setInsertable(jc.insertable());
 652  0
                 join.setNullable(jc.nullable());
 653  0
                 join.setUnique(jc.unique());
 654  0
                 join.setUpdateable(jc.updatable());
 655  0
                 join.setReferencedColumName(jc.referencedColumnName());
 656  0
                 return join;
 657  
         }
 658  
         
 659  
 }