001/** 002 * Copyright 2005-2016 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.util; 017 018import org.apache.commons.beanutils.NestedNullException; 019import org.apache.commons.beanutils.PropertyUtils; 020import org.apache.commons.lang.StringUtils; 021import org.apache.log4j.Logger; 022import org.apache.ojb.broker.core.proxy.ProxyHelper; 023import org.kuali.rice.core.api.CoreApiServiceLocator; 024import org.kuali.rice.core.api.encryption.EncryptionService; 025import org.kuali.rice.core.api.search.SearchOperator; 026import org.kuali.rice.core.api.util.cache.CopiedObject; 027import org.kuali.rice.core.web.format.CollectionFormatter; 028import org.kuali.rice.core.web.format.FormatException; 029import org.kuali.rice.core.web.format.Formatter; 030import org.kuali.rice.kns.service.KNSServiceLocator; 031import org.kuali.rice.krad.bo.BusinessObject; 032import org.kuali.rice.krad.bo.ExternalizableBusinessObject; 033import org.kuali.rice.krad.bo.PersistableBusinessObject; 034import org.kuali.rice.krad.bo.PersistableBusinessObjectExtension; 035import org.kuali.rice.krad.data.DataObjectWrapper; 036import org.kuali.rice.krad.exception.ClassNotPersistableException; 037import org.kuali.rice.krad.maintenance.MaintenanceUtils; 038import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 039import org.kuali.rice.krad.service.ModuleService; 040import org.kuali.rice.krad.service.PersistenceStructureService; 041 042import javax.persistence.EntityNotFoundException; 043 044import java.beans.PropertyDescriptor; 045import java.io.ByteArrayInputStream; 046import java.io.ByteArrayOutputStream; 047import java.io.ObjectInputStream; 048import java.io.ObjectOutputStream; 049import java.io.Serializable; 050import java.lang.reflect.Field; 051import java.lang.reflect.InvocationTargetException; 052import java.security.GeneralSecurityException; 053import java.security.MessageDigest; 054import java.util.Collection; 055import java.util.Iterator; 056import java.util.List; 057import java.util.Map; 058 059/** 060 * Contains various Object, Proxy, and serialization utilities 061 * 062 * @author Kuali Rice Team (rice.collab@kuali.org) 063 * 064 * @deprecated use new KRAD data framework instead 065 */ 066@Deprecated 067public final class ObjectUtils { 068 private static final Logger LOG = Logger.getLogger(ObjectUtils.class); 069 070 private ObjectUtils() { 071 throw new UnsupportedOperationException("do not call"); 072 } 073 074 /** 075 * Uses Serialization mechanism to create a deep copy of the given Object. As a special case, deepCopy of null 076 * returns null, 077 * just to make using this method simpler. For a detailed discussion see: 078 * http://www.javaworld.com/javaworld/javatips/jw-javatip76.html 079 * 080 * @param src 081 * @return deep copy of the given Serializable 082 */ 083 public static Serializable deepCopy(Serializable src) { 084 CopiedObject co = deepCopyForCaching(src); 085 return co.getContent(); 086 } 087 088 /** 089 * Uses Serialization mechanism to create a deep copy of the given Object, and returns a CacheableObject instance 090 * containing the 091 * deepCopy and its size in bytes. As a special case, deepCopy of null returns a cacheableObject containing null and 092 * a size of 093 * 0, to make using this method simpler. For a detailed discussion see: 094 * http://www.javaworld.com/javaworld/javatips/jw-javatip76.html 095 * 096 * @param src 097 * @return CopiedObject containing a deep copy of the given Serializable and its size in bytes 098 */ 099 public static CopiedObject deepCopyForCaching(Serializable src) { 100 CopiedObject co = new CopiedObject(); 101 102 co.setContent(src); 103 104 return co; 105 } 106 107 /** 108 * Converts the object to a byte array using the output stream. 109 * 110 * @param object 111 * @return byte array of the object 112 */ 113 public static byte[] toByteArray(Object object) throws Exception { 114 ObjectOutputStream oos = null; 115 try { 116 ByteArrayOutputStream bos = new ByteArrayOutputStream(); // A 117 oos = new ObjectOutputStream(bos); // B 118 // serialize and pass the object 119 oos.writeObject(object); // C 120 // oos.flush(); // D 121 return bos.toByteArray(); 122 } catch (Exception e) { 123 LOG.warn("Exception in ObjectUtil = " + e); 124 throw (e); 125 } finally { 126 if (oos != null) { 127 oos.close(); 128 } 129 } 130 } 131 132 /** 133 * reconsitiutes the object that was converted into a byte array by toByteArray 134 * 135 * @param bytes 136 * @return 137 * @throws Exception 138 */ 139 public static Object fromByteArray(byte[] bytes) throws Exception { 140 ObjectInputStream ois = null; 141 try { 142 ByteArrayInputStream bis = new ByteArrayInputStream(bytes); 143 ois = new ObjectInputStream(bis); 144 Object obj = ois.readObject(); 145 return obj; 146 } catch (Exception e) { 147 LOG.warn("Exception in ObjectUtil = " + e); 148 throw (e); 149 } finally { 150 if (ois != null) { 151 ois.close(); 152 } 153 } 154 } 155 156 /** 157 * use MD5 to create a one way hash of an object 158 * 159 * @param object 160 * @return 161 */ 162 public static String getMD5Hash(Object object) throws Exception { 163 try { 164 MessageDigest md = MessageDigest.getInstance("MD5"); 165 md.update(toByteArray(object)); 166 return new String(md.digest()); 167 } catch (Exception e) { 168 LOG.warn(e); 169 throw e; 170 } 171 } 172 173 /** 174 * Creates a new instance of a given BusinessObject, copying fields specified in template from the given source BO. 175 * For example, 176 * this can be used to create an AccountChangeDetail based on a particular Account. 177 * 178 * @param template a map defining the relationships between the fields of the newly created BO, and the source BO. 179 * For each K (key), V (value) 180 * entry, the value of property V on the source BO will be assigned to the K property of the newly created BO 181 * @throws NoSuchMethodException 182 * @throws InvocationTargetException 183 * @throws IllegalAccessException 184 * @throws FormatException 185 * @see MaintenanceUtils 186 */ 187 188 public static BusinessObject createHybridBusinessObject(Class businessObjectClass, BusinessObject source, 189 Map<String, String> template) throws FormatException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { 190 BusinessObject obj = null; 191 try { 192 ModuleService moduleService = KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService( 193 businessObjectClass); 194 if (moduleService != null && moduleService.isExternalizable(businessObjectClass)) { 195 obj = moduleService.createNewObjectFromExternalizableClass(businessObjectClass); 196 } else { 197 obj = (BusinessObject) businessObjectClass.newInstance(); 198 } 199 } catch (Exception e) { 200 throw new RuntimeException("Cannot instantiate " + businessObjectClass.getName(), e); 201 } 202 203 createHybridBusinessObject(obj, source, template); 204 205 return obj; 206 } 207 208 public static void createHybridBusinessObject(BusinessObject businessObject, BusinessObject source, 209 Map<String, String> template) throws FormatException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { 210 for (String name : template.keySet()) { 211 String sourcePropertyName = template.get(name); 212 setObjectProperty(businessObject, name, easyGetPropertyType(source, sourcePropertyName), getPropertyValue( 213 source, sourcePropertyName)); 214 } 215 } 216 217 /** 218 * This method simply uses PojoPropertyUtilsBean logic to get the Class of a Class property. 219 * This method does not have any of the logic needed to obtain the Class of an element of a Collection specified in 220 * the DataDictionary. 221 * 222 * @param object An instance of the Class of which we're trying to get the property Class. 223 * @param propertyName The name of the property. 224 * @return 225 * @throws IllegalAccessException 226 * @throws NoSuchMethodException 227 * @throws InvocationTargetException 228 */ 229 static public Class easyGetPropertyType(Object object, 230 String propertyName) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { 231 232 // FIXME (laran) This dependence should be inverted. Instead of having a core class 233 // depend on PojoPropertyUtilsBean, which is in the web layer, the web layer 234 // should depend downward to the core. 235 return PropertyUtils.getPropertyType(object, propertyName); 236 237 } 238 239 /** 240 * Returns the type of the property in the object. This implementation is not smart enough to look through a 241 * Collection to get the property type 242 * of an attribute of an element in the collection. 243 * <p/> 244 * NOTE: A patch file attached to https://test.kuali.org/jira/browse/KULRNE-4435 contains a modified version of this 245 * method which IS smart enough 246 * to look through Collections. This patch is currently under review. 247 * 248 * @param object An instance of the Class for which we're trying to get the property type. 249 * @param propertyName The name of the property of the Class the Class of which we're trying to get. Dot notation is 250 * used to separate properties. 251 * TODO: The rules about this dot notation needs to be explained in Confluence using examples. 252 * @param persistenceStructureService Needed to get the type of elements in a Collection from OJB. 253 * @return Object will be null if any parent property for the given property is null. 254 */ 255 @Deprecated 256 public static Class getPropertyType(Object object, String propertyName, 257 PersistenceStructureService persistenceStructureService) { 258 if (object == null || propertyName == null) { 259 throw new RuntimeException("Business object and property name can not be null"); 260 } 261 262 Class propertyType = null; 263 try { 264 try { 265 // Try to simply use the default or simple way of getting the property type. 266 propertyType = PropertyUtils.getPropertyType(object, propertyName); 267 } catch (IllegalArgumentException ex) { 268 // swallow the exception, propertyType stays null 269 } catch (NoSuchMethodException nsme) { 270 // swallow the exception, propertyType stays null 271 } 272 273 // if the property type as determined from the object is PersistableBusinessObject, 274 // then this must be an extension attribute -- attempt to get the property type from the 275 // persistence structure service 276 if (propertyType != null && propertyType.equals(PersistableBusinessObjectExtension.class)) { 277 propertyType = persistenceStructureService.getBusinessObjectAttributeClass(ProxyHelper.getRealClass( 278 object), propertyName); 279 } 280 281 // If the easy way didn't work ... 282 if (null == propertyType && -1 != propertyName.indexOf('.')) { 283 if (null == persistenceStructureService) { 284 LOG.info( 285 "PropertyType couldn't be determined simply and no PersistenceStructureService was given. If you pass in a PersistenceStructureService I can look in other places to try to determine the type of the property."); 286 } else { 287 String prePeriod = StringUtils.substringBefore(propertyName, "."); 288 String postPeriod = StringUtils.substringAfter(propertyName, "."); 289 290 Class prePeriodClass = getPropertyType(object, prePeriod, persistenceStructureService); 291 Object prePeriodClassInstance = prePeriodClass.newInstance(); 292 propertyType = getPropertyType(prePeriodClassInstance, postPeriod, persistenceStructureService); 293 } 294 295 } else if (Collection.class.isAssignableFrom(propertyType)) { 296 Map<String, Class> map = persistenceStructureService.listCollectionObjectTypes(object.getClass()); 297 propertyType = map.get(propertyName); 298 } 299 300 } catch (Exception e) { 301 LOG.debug("unable to get property type for " + propertyName + " " + e.getMessage()); 302 // continue and return null for propertyType 303 } 304 305 return propertyType; 306 } 307 308 /** 309 * Returns the value of the property in the object. 310 * 311 * @param businessObject 312 * @param propertyName 313 * @return Object will be null if any parent property for the given property is null. 314 * 315 * @deprecated use {@link org.kuali.rice.krad.data.DataObjectWrapper#getPropertyValueNullSafe(String)} instead 316 */ 317 @Deprecated 318 public static Object getPropertyValue(Object businessObject, String propertyName) { 319 if (businessObject == null || propertyName == null) { 320 throw new RuntimeException("Business object and property name can not be null"); 321 } 322 323 Object propertyValue = null; 324 try { 325 propertyValue = PropertyUtils.getProperty(businessObject, propertyName); 326 } catch (NestedNullException e) { 327 // continue and return null for propertyValue 328 } catch (IllegalAccessException e1) { 329 LOG.error("error getting property value for " + businessObject.getClass() + "." + propertyName + " " + e1 330 .getMessage()); 331 throw new RuntimeException( 332 "error getting property value for " + businessObject.getClass() + "." + propertyName + " " + e1 333 .getMessage(), e1); 334 } catch (InvocationTargetException e1) { 335 // continue and return null for propertyValue 336 } catch (NoSuchMethodException e1) { 337 LOG.error("error getting property value for " + businessObject.getClass() + "." + propertyName + " " + e1 338 .getMessage()); 339 throw new RuntimeException( 340 "error getting property value for " + businessObject.getClass() + "." + propertyName + " " + e1 341 .getMessage(), e1); 342 } 343 344 return propertyValue; 345 } 346 347 /** 348 * Gets the property value from the business object, then based on the value 349 * type select a formatter and format the value 350 * 351 * @param businessObject BusinessObject instance that contains the property 352 * @param propertyName Name of property in BusinessObject to get value for 353 * @param formatter Default formatter to use (or null) 354 * @return Formatted property value as String, or empty string if value is null 355 */ 356 @Deprecated 357 public static String getFormattedPropertyValue(BusinessObject businessObject, String propertyName, 358 Formatter formatter) { 359 String propValue = KRADConstants.EMPTY_STRING; 360 361 Object prop = ObjectUtils.getPropertyValue(businessObject, propertyName); 362 if (formatter == null) { 363 propValue = formatPropertyValue(prop); 364 } else { 365 final Object formattedValue = formatter.format(prop); 366 if (formattedValue != null) { 367 propValue = String.valueOf(formattedValue); 368 } 369 } 370 371 return propValue; 372 } 373 374 /** 375 * References the data dictionary to find any registered formatter class then if not found checks for associated 376 * formatter for the 377 * property type. Value is then formatted using the found Formatter 378 * 379 * @param businessObject BusinessObject instance that contains the property 380 * @param propertyName Name of property in BusinessObject to get value for 381 * @return Formatted property value as String, or empty string if value is null 382 */ 383 public static String getFormattedPropertyValueUsingDataDictionary(BusinessObject businessObject, 384 String propertyName) { 385 Formatter formatter = getFormatterWithDataDictionary(businessObject, propertyName); 386 387 return getFormattedPropertyValue(businessObject, propertyName, formatter); 388 } 389 390 /** 391 * Based on the value type selects a formatter and returns the formatted 392 * value as a string 393 * 394 * @param propertyValue Object value to be formatted 395 * @return formatted value as a String 396 */ 397 public static String formatPropertyValue(Object propertyValue) { 398 Object propValue = KRADConstants.EMPTY_STRING; 399 400 Formatter formatter = null; 401 if (propertyValue != null) { 402 if (propertyValue instanceof Collection) { 403 formatter = new CollectionFormatter(); 404 } else { 405 formatter = Formatter.getFormatter(propertyValue.getClass()); 406 } 407 408 propValue = formatter != null ? formatter.format(propertyValue) : propertyValue; 409 } 410 411 return propValue != null ? String.valueOf(propValue) : KRADConstants.EMPTY_STRING; 412 } 413 414 /** 415 * Sets the property of an object with the given value. Converts using the formatter of the type for the property. 416 * Note: propertyType does not need passed, is found by util method. 417 */ 418 public static void setObjectProperty(Object bo, String propertyName, 419 Object propertyValue) throws FormatException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { 420 Class propertyType = easyGetPropertyType(bo, propertyName); 421 setObjectProperty(bo, propertyName, propertyType, propertyValue); 422 } 423 424 /** 425 * Sets the property of an object with the given value. Converts using the formatter of the given type if one is 426 * found. 427 * 428 * @param bo 429 * @param propertyName 430 * @param propertyType 431 * @param propertyValue 432 * @throws NoSuchMethodException 433 * @throws InvocationTargetException 434 * @throws IllegalAccessException 435 */ 436 public static void setObjectProperty(Object bo, String propertyName, Class propertyType, 437 Object propertyValue) throws FormatException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { 438 // reformat propertyValue, if necessary 439 boolean reformat = false; 440 if (propertyType != null) { 441 if (propertyValue != null && propertyType.isAssignableFrom(String.class)) { 442 // always reformat if the destination is a String 443 reformat = true; 444 } else if (propertyValue != null && !propertyType.isAssignableFrom(propertyValue.getClass())) { 445 // otherwise, only reformat if the propertyValue can't be assigned into the property 446 reformat = true; 447 } 448 449 // attempting to set boolean fields to null throws an exception, set to false instead 450 if (boolean.class.isAssignableFrom(propertyType) && propertyValue == null) { 451 propertyValue = false; 452 } 453 } 454 455 Formatter formatter = getFormatterWithDataDictionary(bo, propertyName); 456 if (reformat && formatter != null) { 457 LOG.debug("reformatting propertyValue using Formatter " + formatter.getClass().getName()); 458 propertyValue = formatter.convertFromPresentationFormat(propertyValue); 459 } 460 461 // set property in the object 462 PropertyUtils.setNestedProperty(bo, propertyName, propertyValue); 463 } 464 465 /** 466 * Sets the property of an object with the given value. Converts using the given formatter, if it isn't null. 467 * 468 * @param formatter 469 * @param bo 470 * @param propertyName 471 * @param type 472 * @param propertyValue 473 * @throws NoSuchMethodException 474 * @throws InvocationTargetException 475 * @throws IllegalAccessException 476 */ 477 public static void setObjectProperty(Formatter formatter, Object bo, String propertyName, Class type, 478 Object propertyValue) throws FormatException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { 479 480 // convert value using formatter for type 481 if (formatter != null) { 482 propertyValue = formatter.convertFromPresentationFormat(propertyValue); 483 } 484 485 // KULRICE-8412 Changes so that values passed back through via the URL such as 486 // lookups are decrypted where applicable 487 if (propertyValue instanceof String) { 488 String propVal = (String) propertyValue; 489 490 if (propVal.endsWith(EncryptionService.ENCRYPTION_POST_PREFIX)) { 491 propVal = StringUtils.removeEnd(propVal, EncryptionService.ENCRYPTION_POST_PREFIX); 492 } 493 494 if (KNSServiceLocator.getBusinessObjectAuthorizationService().attributeValueNeedsToBeEncryptedOnFormsAndLinks(bo.getClass(), propertyName)) { 495 try { 496 if (CoreApiServiceLocator.getEncryptionService().isEnabled()) { 497 propertyValue = CoreApiServiceLocator.getEncryptionService().decrypt(propVal); 498 } 499 } catch (GeneralSecurityException e) { 500 throw new RuntimeException(e); 501 } 502 } 503 } 504 505 // set property in the object 506 PropertyUtils.setNestedProperty(bo, propertyName, propertyValue); 507 } 508 509 /** 510 * Returns a Formatter instance for the given property name in the given given business object. First 511 * checks if a formatter is defined for the attribute in the data dictionary, is not found then returns 512 * the registered formatter for the property type in Formatter 513 * 514 * @param bo - business object instance with property to get formatter for 515 * @param propertyName - name of property to get formatter for 516 * @return Formatter instance 517 */ 518 @Deprecated 519 public static Formatter getFormatterWithDataDictionary(Object bo, String propertyName) { 520 Formatter formatter = null; 521 522 Class boClass = bo.getClass(); 523 String boPropertyName = propertyName; 524 525 // for collections, formatter should come from property on the collection type 526 if (StringUtils.contains(propertyName, "]")) { 527 Object collectionParent = getNestedValue(bo, StringUtils.substringBeforeLast(propertyName, "].") + "]"); 528 if (collectionParent != null) { 529 boClass = collectionParent.getClass(); 530 boPropertyName = StringUtils.substringAfterLast(propertyName, "]."); 531 } 532 } 533 534 Class<? extends Formatter> formatterClass = 535 KRADServiceLocatorWeb.getDataDictionaryService().getAttributeFormatter(boClass, boPropertyName); 536 if (formatterClass == null) { 537 try { 538 formatterClass = Formatter.findFormatter(getPropertyType(boClass.newInstance(), boPropertyName, 539 KNSServiceLocator.getPersistenceStructureService())); 540 } catch (InstantiationException e) { 541 LOG.warn("Unable to find a formater for bo class " + boClass + " and property " + boPropertyName); 542 // just swallow the exception and let formatter be null 543 } catch (IllegalAccessException e) { 544 LOG.warn("Unable to find a formater for bo class " + boClass + " and property " + boPropertyName); 545 // just swallow the exception and let formatter be null 546 } 547 } 548 549 if (formatterClass != null) { 550 try { 551 formatter = formatterClass.newInstance(); 552 } catch (Exception e) { 553 throw new RuntimeException("cannot create new instance of formatter class " + formatterClass.toString(), 554 e); 555 } 556 } 557 558 return formatter; 559 } 560 561 /** 562 * Recursive; sets all occurences of the property in the object, its nested objects and its object lists with the 563 * given value. 564 * 565 * @param bo 566 * @param propertyName 567 * @param type 568 * @param propertyValue 569 * @throws NoSuchMethodException 570 * @throws InvocationTargetException 571 * @throws IllegalAccessException 572 */ 573 public static void setObjectPropertyDeep(Object bo, String propertyName, Class type, 574 Object propertyValue) throws FormatException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { 575 576 // Base return cases to avoid null pointers & infinite loops 577 if (isNull(bo) || !PropertyUtils.isReadable(bo, propertyName) || (propertyValue != null && propertyValue.equals( 578 getPropertyValue(bo, propertyName))) || (type != null && !type.equals(easyGetPropertyType(bo, 579 propertyName)))) { 580 return; 581 } 582 583 // Removed this as the two remaining locations which call this are now performing the refresh themselves 584 // need to materialize the updateable collections before resetting the property, because it may be used in the retrieval 585 //materializeUpdateableCollections(bo); 586 587 // Set the property in the BO 588 setObjectProperty(bo, propertyName, type, propertyValue); 589 590 // Now drill down and check nested BOs and BO lists 591 PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(bo.getClass()); 592 for (int i = 0; i < propertyDescriptors.length; i++) { 593 594 PropertyDescriptor propertyDescriptor = propertyDescriptors[i]; 595 596 // Business Objects 597 if (propertyDescriptor.getPropertyType() != null && (BusinessObject.class).isAssignableFrom( 598 propertyDescriptor.getPropertyType()) && PropertyUtils.isReadable(bo, 599 propertyDescriptor.getName())) { 600 Object nestedBo = getPropertyValue(bo, propertyDescriptor.getName()); 601 if (nestedBo instanceof BusinessObject) { 602 setObjectPropertyDeep(nestedBo, propertyName, type, propertyValue); 603 } 604 } 605 606 // Lists 607 else if (propertyDescriptor.getPropertyType() != null && (List.class).isAssignableFrom( 608 propertyDescriptor.getPropertyType()) && getPropertyValue(bo, propertyDescriptor.getName()) 609 != null) { 610 611 List propertyList = (List) getPropertyValue(bo, propertyDescriptor.getName()); 612 for (Object listedBo : propertyList) { 613 if (listedBo != null && listedBo instanceof BusinessObject) { 614 setObjectPropertyDeep(listedBo, propertyName, type, propertyValue); 615 } 616 } // end for 617 } 618 } // end for 619 } 620 621 /* 622 * Recursive up to a given depth; sets all occurrences of the property in the object, its nested objects and its object lists with the given value. 623 */ 624 public static void setObjectPropertyDeep(Object bo, String propertyName, Class type, Object propertyValue, 625 int depth) throws FormatException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { 626 // Base return cases to avoid null pointers & infinite loops 627 if (depth == 0 || isNull(bo) || !PropertyUtils.isReadable(bo, propertyName)) { 628 return; 629 } 630 631 // Removed this as the two remaining locations which call this are now performing the refresh themselves 632 633 // need to materialize the updateable collections before resetting the property, because it may be used in the retrieval 634// try { 635// materializeUpdateableCollections(bo); 636// } catch(ClassNotPersistableException ex){ 637// //Not all classes will be persistable in a collection. For e.g. externalizable business objects. 638// LOG.info("Not persistable dataObjectClass: "+bo.getClass().getName()+", field: "+propertyName); 639// } 640 641 // Set the property in the BO 642 setObjectProperty(bo, propertyName, type, propertyValue); 643 644 // Now drill down and check nested BOs and BO lists 645 PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(bo.getClass()); 646 for (int i = 0; i < propertyDescriptors.length; i++) { 647 PropertyDescriptor propertyDescriptor = propertyDescriptors[i]; 648 649 // Business Objects 650 if (propertyDescriptor.getPropertyType() != null && (BusinessObject.class).isAssignableFrom( 651 propertyDescriptor.getPropertyType()) && PropertyUtils.isReadable(bo, 652 propertyDescriptor.getName())) { 653 Object nestedBo = getPropertyValue(bo, propertyDescriptor.getName()); 654 if (nestedBo instanceof BusinessObject) { 655 setObjectPropertyDeep(nestedBo, propertyName, type, propertyValue, depth - 1); 656 } 657 } 658 659 // Lists 660 else if (propertyDescriptor.getPropertyType() != null && (List.class).isAssignableFrom( 661 propertyDescriptor.getPropertyType()) && getPropertyValue(bo, propertyDescriptor.getName()) 662 != null) { 663 664 List propertyList = (List) getPropertyValue(bo, propertyDescriptor.getName()); 665 666 // Complete Hibernate Hack - fetches the proxied List into the PersistenceContext and sets it on the BO Copy. 667// if (propertyList instanceof PersistentBag) { 668// try { 669// PersistentBag bag = (PersistentBag) propertyList; 670// PersistableBusinessObject pbo = 671// (PersistableBusinessObject) KRADServiceLocator.getEntityManagerFactory() 672// .createEntityManager().find(bo.getClass(), bag.getKey()); 673// Field field1 = pbo.getClass().getDeclaredField(propertyDescriptor.getName()); 674// Field field2 = bo.getClass().getDeclaredField(propertyDescriptor.getName()); 675// field1.setAccessible(true); 676// field2.setAccessible(true); 677// field2.set(bo, field1.get(pbo)); 678// propertyList = (List) getPropertyValue(bo, propertyDescriptor.getName()); 679// ; 680// } catch (Exception e) { 681// LOG.error(e.getMessage(), e); 682// } 683// } 684 // End Complete Hibernate Hack 685 686 for (Object listedBo : propertyList) { 687 if (listedBo != null && listedBo instanceof BusinessObject) { 688 setObjectPropertyDeep(listedBo, propertyName, type, propertyValue, depth - 1); 689 } 690 } // end for 691 } 692 } // end for 693 } 694 695 /** 696 * This method checks for updateable collections on the business object provided and materializes the corresponding 697 * collection proxies 698 * 699 * @param bo The business object for which you want unpdateable, proxied collections materialized 700 * @throws FormatException 701 * @throws IllegalAccessException 702 * @throws InvocationTargetException 703 * @throws NoSuchMethodException 704 * 705 * @deprecated Replaced by {@link DataObjectWrapper#materializeReferencedObjects(org.kuali.rice.krad.data.MaterializeOption...)} 706 */ 707 @Deprecated 708 public static void materializeUpdateableCollections( 709 Object bo) throws FormatException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { 710 if (isNotNull(bo)) { 711 PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(bo.getClass()); 712 for (int i = 0; i < propertyDescriptors.length; i++) { 713 if (KNSServiceLocator.getPersistenceStructureService().hasCollection(bo.getClass(), 714 propertyDescriptors[i].getName()) && KNSServiceLocator.getPersistenceStructureService() 715 .isCollectionUpdatable(bo.getClass(), propertyDescriptors[i].getName())) { 716 Collection updateableCollection = (Collection) getPropertyValue(bo, 717 propertyDescriptors[i].getName()); 718 if ((updateableCollection != null) && ProxyHelper.isCollectionProxy(updateableCollection)) { 719 materializeObjects(updateableCollection); 720 } 721 } 722 } 723 } 724 } 725 726 /** 727 * Removes all query characters from a string. 728 * 729 * @param string 730 * @return Cleaned string 731 */ 732 public static String clean(String string) { 733 for (SearchOperator op : SearchOperator.QUERY_CHARACTERS) { 734 string = StringUtils.replace(string, op.op(), KRADConstants.EMPTY_STRING); 735 } 736 return string; 737 } 738 739 /** 740 * Compares two {@link PersistableBusinessObject} instances for equality of type and key values. 741 * 742 * @param bo1 743 * @param bo2 744 * @return boolean indicating whether the two objects are equal. 745 * 746 * @deprecated use {@link org.kuali.rice.krad.data.DataObjectWrapper#equalsByPrimaryKey(Object)} 747 */ 748 @Deprecated 749 public static boolean equalByKeys(PersistableBusinessObject bo1, PersistableBusinessObject bo2) { 750 boolean equal = true; 751 752 if (bo1 == null && bo2 == null) { 753 equal = true; 754 } else if (bo1 == null || bo2 == null) { 755 equal = false; 756 } else if (!bo1.getClass().getName().equals(bo2.getClass().getName())) { 757 equal = false; 758 } else { 759 Map bo1Keys = KNSServiceLocator.getPersistenceService().getPrimaryKeyFieldValues(bo1); 760 Map bo2Keys = KNSServiceLocator.getPersistenceService().getPrimaryKeyFieldValues(bo2); 761 for (Iterator iter = bo1Keys.keySet().iterator(); iter.hasNext(); ) { 762 String keyName = (String) iter.next(); 763 if (bo1Keys.get(keyName) != null && bo2Keys.get(keyName) != null) { 764 if (!bo1Keys.get(keyName).toString().equals(bo2Keys.get(keyName).toString())) { 765 equal = false; 766 } 767 } else { 768 equal = false; 769 } 770 } 771 } 772 773 return equal; 774 } 775 776 /** 777 * Compares a business object with a List of {@link PersistableBusinessObject}s to determine if an object with the 778 * same key as the BO exists in the list. 779 * 780 * @param controlList - The list of items to check 781 * @param bo - The BO whose keys we are looking for in the controlList 782 * @return boolean 783 */ 784 @Deprecated 785 public static boolean collectionContainsObjectWithIdentitcalKey( 786 Collection<? extends PersistableBusinessObject> controlList, PersistableBusinessObject bo) { 787 boolean objectExistsInList = false; 788 789 for (Iterator i = controlList.iterator(); i.hasNext(); ) { 790 if (equalByKeys((PersistableBusinessObject) i.next(), bo)) { 791 return true; 792 } 793 } 794 795 return objectExistsInList; 796 } 797 798 /** 799 * Compares a business object with a Collection of {@link PersistableBusinessObject}s to count how many have the 800 * same key as the BO. 801 * 802 * @param collection - The collection of items to check 803 * @param bo - The BO whose keys we are looking for in the collection 804 * @return how many have the same keys 805 */ 806 public static int countObjectsWithIdentitcalKey(Collection<? extends PersistableBusinessObject> collection, 807 PersistableBusinessObject bo) { 808 // todo: genericize collectionContainsObjectWithIdentitcalKey() to leverage this method? 809 int n = 0; 810 for (PersistableBusinessObject item : collection) { 811 if (equalByKeys(item, bo)) { 812 n++; 813 } 814 } 815 return n; 816 } 817 818 /** 819 * Compares a business object with a List of {@link PersistableBusinessObject}s to determine if an object with the 820 * same key as the BO exists in the list. If it 821 * does, the item is removed from the List. This is functionally similar to List.remove() that operates only on Key 822 * values. 823 * 824 * @param controlList - The list of items to check 825 * @param bo - The BO whose keys we are looking for in the controlList 826 * 827 * @deprecated there is no replacement for this method 828 */ 829 @Deprecated 830 public static void removeObjectWithIdentitcalKey(Collection<? extends PersistableBusinessObject> controlList, 831 PersistableBusinessObject bo) { 832 for (Iterator<? extends PersistableBusinessObject> i = controlList.iterator(); i.hasNext(); ) { 833 PersistableBusinessObject listBo = i.next(); 834 if (equalByKeys(listBo, bo)) { 835 i.remove(); 836 } 837 } 838 } 839 840 /** 841 * Compares a business object with a List of BOs to determine if an object with the same key as the BO exists in the 842 * list. If it 843 * does, the item is returned. 844 * 845 * @param controlList - The list of items to check 846 * @param bo - The BO whose keys we are looking for in the controlList 847 * 848 * @deprecated there is no replacement for this method 849 */ 850 @Deprecated 851 public static BusinessObject retrieveObjectWithIdentitcalKey( 852 Collection<? extends PersistableBusinessObject> controlList, PersistableBusinessObject bo) { 853 BusinessObject returnBo = null; 854 855 for (Iterator<? extends PersistableBusinessObject> i = controlList.iterator(); i.hasNext(); ) { 856 PersistableBusinessObject listBo = i.next(); 857 if (equalByKeys(listBo, bo)) { 858 returnBo = listBo; 859 } 860 } 861 862 return returnBo; 863 } 864 865 /** 866 * Determines if a given string could represent a nested attribute of an object. 867 * 868 * @param attributeName 869 * @return true if the attribute is nested 870 */ 871 public static boolean isNestedAttribute(String attributeName) { 872 boolean isNested = false; 873 874 if (StringUtils.contains(attributeName, ".")) { 875 isNested = true; 876 } 877 878 return isNested; 879 } 880 881 /** 882 * Returns the prefix of a nested attribute name, or the empty string if the attribute name is not nested. 883 * 884 * @param attributeName 885 * @return everything BEFORE the last "." character in attributeName 886 */ 887 public static String getNestedAttributePrefix(String attributeName) { 888 String prefix = ""; 889 890 if (StringUtils.contains(attributeName, ".")) { 891 prefix = StringUtils.substringBeforeLast(attributeName, "."); 892 } 893 894 return prefix; 895 } 896 897 /** 898 * Returns the primitive part of an attribute name string. 899 * 900 * @param attributeName 901 * @return everything AFTER the last "." character in attributeName 902 */ 903 public static String getNestedAttributePrimitive(String attributeName) { 904 String primitive = attributeName; 905 906 if (StringUtils.contains(attributeName, ".")) { 907 primitive = StringUtils.substringAfterLast(attributeName, "."); 908 } 909 910 return primitive; 911 } 912 913 /** 914 * This method is a OJB Proxy-safe way to test for null on a proxied object that may or may not be materialized yet. 915 * It is safe 916 * to use on a proxy (materialized or non-materialized) or on a non-proxy (ie, regular object). Note that this will 917 * force a 918 * materialization of the proxy if the object is a proxy and unmaterialized. 919 * 920 * @param object - any object, proxied or not, materialized or not 921 * @return true if the object (or underlying materialized object) is null, false otherwise 922 */ 923 public static boolean isNull(Object object) { 924 925 // regardless, if its null, then its null 926 if (object == null) { 927 return true; 928 } 929 930 // only try to materialize the object to see if its null if this is a 931 // proxy object 932 if (ProxyHelper.isProxy(object) || ProxyHelper.isCollectionProxy(object)) { 933 if (ProxyHelper.getRealObject(object) == null) { 934 return true; 935 } 936 } 937 938 // JPA does not provide a way to determine if an object is a proxy, instead we invoke 939 // the equals method and catch an EntityNotFoundException 940 try { 941 object.equals(null); 942 } catch (EntityNotFoundException e) { 943 return true; 944 } 945 946 return false; 947 } 948 949 /** 950 * This method is a OJB Proxy-safe way to test for notNull on a proxied object that may or may not be materialized 951 * yet. It is 952 * safe to use on a proxy (materialized or non-materialized) or on a non-proxy (ie, regular object). Note that this 953 * will force a 954 * materialization of the proxy if the object is a proxy and unmaterialized. 955 * 956 * @param object - any object, proxied or not, materialized or not 957 * @return true if the object (or underlying materialized object) is not null, true if its null 958 */ 959 public static boolean isNotNull(Object object) { 960 return !ObjectUtils.isNull(object); 961 } 962 963 /** 964 * Attempts to find the Class for the given potentially proxied object 965 * 966 * @param object the potentially proxied object to find the Class of 967 * @return the best Class which could be found for the given object 968 */ 969 public static Class materializeClassForProxiedObject(Object object) { 970 if (object == null) { 971 return null; 972 } 973 974// if (object instanceof HibernateProxy) { 975// final Class realClass = ((HibernateProxy) object).getHibernateLazyInitializer().getPersistentClass(); 976// return realClass; 977// } 978 979 if (ProxyHelper.isProxy(object) || ProxyHelper.isCollectionProxy(object)) { 980 return ProxyHelper.getRealClass(object); 981 } 982 983 return object.getClass(); 984 } 985 986 /** 987 * This method runs the ObjectUtils.isNotNull() method for each item in a list of BOs. ObjectUtils.isNotNull() will 988 * materialize 989 * the objects if they are currently OJB proxies. 990 * 991 * @param possiblyProxiedObjects - a Collection of objects that may be proxies 992 */ 993 public static void materializeObjects(Collection possiblyProxiedObjects) { 994 for (Iterator i = possiblyProxiedObjects.iterator(); i.hasNext(); ) { 995 ObjectUtils.isNotNull(i.next()); 996 } 997 } 998 999 /** 1000 * This method attempts to materialize all of the proxied reference objects (ie, sub-objects) hanging off the 1001 * passed-in BO 1002 * object. It will do it down to the specified depth. An IllegalArgumentException will be thrown if the bo object 1003 * passed in is 1004 * itself a non-materialized proxy object. If the bo passed in has no proxied sub-objects, then the object will not 1005 * be modified, 1006 * and no errors will be thrown. WARNING: Be careful using depth any greater than 2. The number of DB hits, time, 1007 * and memory 1008 * consumed grows exponentially with each additional increment to depth. Make sure you really need that depth before 1009 * doing so. 1010 * 1011 * @param bo A valid, populated BusinessObject containing (possibly) proxied sub-objects. This object will be 1012 * modified in place. 1013 * @param depth int Value 0-5 indicating how deep to recurse the materialization. If a zero (0) is passed in, then 1014 * no work will 1015 * be done. 1016 * 1017 * @deprecated Replaced by {@link DataObjectWrapper#materializeReferencedObjectsToDepth(int, org.kuali.rice.krad.data.MaterializeOption...)} 1018 */ 1019 @Deprecated 1020 public static void materializeSubObjectsToDepth(PersistableBusinessObject bo, int depth) { 1021 if (bo == null) { 1022 throw new IllegalArgumentException("The bo passed in was null."); 1023 } 1024 if (depth < 0 || depth > 5) { 1025 throw new IllegalArgumentException("The depth passed in was out of bounds. Only values " 1026 + "between 0 and 5, inclusively, are allowed."); 1027 } 1028 1029 // if depth is zero, then we're done recursing and can just exit 1030 if (depth == 0) { 1031 return; 1032 } 1033 1034 // deal with the possibility that the bo passed in (ie, the parent object) is an un-materialized proxy 1035 if (ProxyHelper.isProxy(bo)) { 1036 if (!ProxyHelper.isMaterialized(bo)) { 1037 throw new IllegalArgumentException("The bo passed in is an un-materialized proxy, and cannot be used."); 1038 } 1039 } 1040 1041 // get the list of reference objects hanging off the parent BO 1042 if (KRADServiceLocatorWeb.getLegacyDataAdapter().isPersistable(bo.getClass())) { 1043 Map<String, Class> references = 1044 KNSServiceLocator.getPersistenceStructureService().listReferenceObjectFields(bo); 1045 1046 // initialize our in-loop objects 1047 String referenceName = ""; 1048 Class referenceClass = null; 1049 Object referenceValue = null; 1050 Object realReferenceValue = null; 1051 1052 // for each reference object on the parent bo 1053 for (Iterator iter = references.keySet().iterator(); iter.hasNext(); ) { 1054 referenceName = (String) iter.next(); 1055 referenceClass = references.get(referenceName); 1056 1057 // if its a proxy, replace it with a non-proxy 1058 referenceValue = getPropertyValue(bo, referenceName); 1059 if (referenceValue != null) { 1060 if (ProxyHelper.isProxy(referenceValue)) { 1061 realReferenceValue = ProxyHelper.getRealObject(referenceValue); 1062 if (realReferenceValue != null) { 1063 try { 1064 setObjectProperty(bo, referenceName, referenceClass, realReferenceValue); 1065 } catch (FormatException e) { 1066 throw new RuntimeException( 1067 "FormatException: could not set the property '" + referenceName + "'.", e); 1068 } catch (IllegalAccessException e) { 1069 throw new RuntimeException( 1070 "IllegalAccessException: could not set the property '" + referenceName + "'.", 1071 e); 1072 } catch (InvocationTargetException e) { 1073 throw new RuntimeException("InvocationTargetException: could not set the property '" 1074 + referenceName 1075 + "'.", e); 1076 } catch (NoSuchMethodException e) { 1077 throw new RuntimeException( 1078 "NoSuchMethodException: could not set the property '" + referenceName + "'.", 1079 e); 1080 } 1081 } 1082 } 1083 1084 // recurse down through this reference object 1085 if (realReferenceValue instanceof PersistableBusinessObject && depth > 1) { 1086 materializeSubObjectsToDepth((PersistableBusinessObject) realReferenceValue, depth - 1); 1087 } 1088 } 1089 1090 } 1091 } 1092 } 1093 1094 /** 1095 * This method attempts to materialize all of the proxied reference objects (ie, sub-objects) hanging off the 1096 * passed-in BO 1097 * object. It will do it just three levels down. In other words, it will only materialize the objects that are 1098 * direct members of 1099 * the bo, objects that are direct members of those bos, that one more time, and no further down. An 1100 * IllegalArgumentException 1101 * will be thrown if the bo object passed in is itself a non-materialized proxy object. If the bo passed in has no 1102 * proxied 1103 * sub-objects, then the object will not be modified, and no errors will be thrown. 1104 * 1105 * @param bo A valid, populated BusinessObject containing (possibly) proxied sub-objects. This object will be 1106 * modified in place. 1107 * 1108 * @deprecated Replaced by {@link DataObjectWrapper#materializeReferencedObjectsToDepth(int, org.kuali.rice.krad.data.MaterializeOption...)} 1109 */ 1110 @Deprecated 1111 public static void materializeAllSubObjects(PersistableBusinessObject bo) { 1112 materializeSubObjectsToDepth(bo, 3); 1113 } 1114 1115 /** 1116 * This method safely extracts either simple values OR nested values. For example, if the bo is SubAccount, and the 1117 * fieldName is 1118 * a21SubAccount.subAccountTypeCode, this thing makes sure it gets the value off the very end attribute, no matter 1119 * how deeply 1120 * nested it is. The code would be slightly simpler if this was done recursively, but this is safer, and consumes a 1121 * constant 1122 * amount of memory, no matter how deeply nested it goes. 1123 * 1124 * @param bo 1125 * @param fieldName 1126 * @return The field value if it exists. If it doesnt, and the name is invalid, and 1127 */ 1128 public static Object getNestedValue(Object bo, String fieldName) { 1129 1130 if (bo == null) { 1131 throw new IllegalArgumentException("The bo passed in was null."); 1132 } 1133 if (StringUtils.isBlank(fieldName)) { 1134 throw new IllegalArgumentException("The fieldName passed in was blank."); 1135 } 1136 1137 // okay, this section of code is to handle sub-object values, like 1138 // SubAccount.a21SubAccount.subAccountTypeCode. it basically walks 1139 // through the period-delimited list of names, and ends up with the 1140 // final value. 1141 String[] fieldNameParts = fieldName.split("\\."); 1142 Object currentObject = null; 1143 Object priorObject = bo; 1144 for (int i = 0; i < fieldNameParts.length; i++) { 1145 String fieldNamePart = fieldNameParts[i]; 1146 1147 try { 1148 if (fieldNamePart.indexOf("]") > 0) { 1149 currentObject = PropertyUtils.getIndexedProperty(priorObject, fieldNamePart); 1150 } else { 1151 currentObject = PropertyUtils.getSimpleProperty(priorObject, fieldNamePart); 1152 } 1153 } catch (IllegalAccessException e) { 1154 throw new RuntimeException("Caller does not have access to the property accessor method.", e); 1155 } catch (InvocationTargetException e) { 1156 throw new RuntimeException("Property accessor method threw an exception.", e); 1157 } catch (NoSuchMethodException e) { 1158 throw new RuntimeException("The accessor method requested for this property cannot be found.", e); 1159 } 1160 1161 // materialize the proxy, if it is a proxy 1162 if (ProxyHelper.isProxy(currentObject)) { 1163 currentObject = ProxyHelper.getRealObject(currentObject); 1164 } 1165 1166 // if a node or the leaf is null, then we're done, there's no need to 1167 // continue accessing null things 1168 if (currentObject == null) { 1169 return currentObject; 1170 } 1171 1172 priorObject = currentObject; 1173 } 1174 return currentObject; 1175 } 1176 1177 /** 1178 * This method safely creates a object from a class 1179 * Convenience method to create new object and throw a runtime exception if it cannot 1180 * If the class is an {@link ExternalizableBusinessObject}, this method will determine the interface for the EBO and 1181 * query the 1182 * appropriate module service to create a new instance. 1183 * 1184 * @param clazz 1185 * @return a newInstance() of clazz 1186 */ 1187 public static Object createNewObjectFromClass(Class clazz) { 1188 if (clazz == null) { 1189 throw new RuntimeException("BO class was passed in as null"); 1190 } 1191 try { 1192 if (ExternalizableBusinessObject.class.isAssignableFrom(clazz)) { 1193 Class eboInterface = 1194 ExternalizableBusinessObjectUtils.determineExternalizableBusinessObjectSubInterface(clazz); 1195 ModuleService moduleService = KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService( 1196 eboInterface); 1197 return moduleService.createNewObjectFromExternalizableClass(eboInterface); 1198 } else { 1199 return clazz.newInstance(); 1200 } 1201 } catch (Exception e) { 1202 throw new RuntimeException("Error occured while trying to create a new instance for class " + clazz, e); 1203 } 1204 } 1205 1206 /** 1207 * Return whether or not an attribute is writeable. This method is aware that that Collections may be involved and 1208 * handles them 1209 * consistently with the way in which OJB handles specifying the attributes of elements of a Collection. 1210 * 1211 * @param object 1212 * @param property 1213 * @return 1214 * @throws IllegalArgumentException 1215 */ 1216 public static boolean isWriteable(Object object, String property, 1217 PersistenceStructureService persistenceStructureService) throws IllegalArgumentException { 1218 if (null == object || null == property) { 1219 throw new IllegalArgumentException("Cannot check writeable status with null arguments."); 1220 } 1221 1222 // Try the easy way. 1223 try { 1224 if (!(PropertyUtils.isWriteable(object, property))) { 1225 // If that fails lets try to be a bit smarter, understanding that Collections may be involved. 1226 return isWriteableHelper(object, property, persistenceStructureService); 1227 } else { 1228 return true; 1229 } 1230 } catch (NestedNullException nestedNullException) { 1231 // If a NestedNullException is thrown then the property has a null 1232 // value. Call the helper to find the class of the property and 1233 // get a newInstance of it. 1234 return isWriteableHelper(object, property, persistenceStructureService); 1235 } 1236 } 1237 1238 /** 1239 * This method handles the cases where PropertyUtils.isWriteable is not 1240 * sufficient. It handles cases where the parameter in question is a 1241 * collection or if the parameter value is null. 1242 * @param object 1243 * @param property 1244 * @param persistenceStructureService 1245 * @return 1246 */ 1247 private static boolean isWriteableHelper(Object object, String property, PersistenceStructureService persistenceStructureService) { 1248 if (property.contains(".")) { 1249 String propertyName = StringUtils.substringBefore(property, "."); 1250 1251 // Get the type of the attribute. 1252 Class<?> c = ObjectUtils.getPropertyType(object, propertyName, persistenceStructureService); 1253 1254 if (c != null) { 1255 Object i = null; 1256 1257 // If the next level is a Collection, look into the collection, to find out what type its elements are. 1258 if (Collection.class.isAssignableFrom(c)) { 1259 Map<String, Class> m = persistenceStructureService.listCollectionObjectTypes(object.getClass()); 1260 c = m.get(propertyName); 1261 } 1262 1263 // Look into the attribute class to see if it is writeable. 1264 try { 1265 i = c.newInstance(); 1266 return isWriteable(i, StringUtils.substringAfter(property, "."), persistenceStructureService); 1267 } catch (Exception ex) { 1268 LOG.error("Skipping Criteria: " + property + " - Unable to instantiate class : " + c.getName(), ex); 1269 } 1270 } else { 1271 LOG.error("Skipping Criteria: " + property + " - Unable to determine class for object: " 1272 + object.getClass().getName() + " - " + propertyName); 1273 } 1274 } 1275 return false; 1276 } 1277 1278 /** 1279 * Helper method for creating a new instance of the given class 1280 * 1281 * @param clazz - class of object to create 1282 * @return T object of type given by the clazz parameter 1283 */ 1284 public static <T> T newInstance(Class<T> clazz) { 1285 T object = null; 1286 try { 1287 object = clazz.newInstance(); 1288 } catch (InstantiationException e) { 1289 LOG.error("Unable to create new instance of class: " + clazz.getName()); 1290 throw new RuntimeException(e); 1291 } catch (IllegalAccessException e) { 1292 LOG.error("Unable to create new instance of class: " + clazz.getName()); 1293 throw new RuntimeException(e); 1294 } 1295 1296 return object; 1297 } 1298 1299 /** 1300 * Retrieves all fields including the inherited fields for a given class. The recursion stops if either Object class is reached 1301 * or if stopAt is reached first. 1302 * 1303 * @param fields List of fields (public, private and protected) 1304 * @param type Class from which fields retrieval has to start 1305 * @param stopAt Parent class where the recursion should stop 1306 * @return 1307 */ 1308 public static List<Field> getAllFields(List<Field> fields, Class<?> type, Class<?> stopAt) { 1309 for (Field field : type.getDeclaredFields()) { 1310 fields.add(field); 1311 } 1312 1313 if (type.getSuperclass() != null && !type.getName().equals(stopAt.getName())) { 1314 fields = getAllFields(fields, type.getSuperclass(), stopAt); 1315 } 1316 1317 return fields; 1318 } 1319 1320}