[jboss-user] [EJB 3.0] - Re: Detach entities - Obtaining a clear pojo

dietice do-not-reply at jboss.com
Sun Jul 6 17:09:33 EDT 2008


Since the challenge still exists, here is an even further improved version.
The behaviour is the same, simply some performance improvements were added.

package org.hibernate.collection;
  | 
  | import java.lang.reflect.InvocationTargetException;
  | import java.util.Collection;
  | import java.util.HashSet;
  | import java.util.Map;
  | 
  | import org.apache.commons.beanutils.PropertyUtils;
  | import org.hibernate.LazyInitializationException;
  | 
  | /**
  |  * Some utility methods to get a complete clean POJO from an entity bean with hibernate 
  |  * specific fields stripped out. Note this class is not meant as a way of avoid 
  |  * LazyInitializationException's.
  |  * Its purpose to strip out data before sending the object to a remote client so that 
  |  * does not have knowledge of hibernate classes. 
  |  * @author ALR 5/9/2006
  |  * @author modified by James Adams 6/9/2006, 7/9/2006
  |  * @author me 7/6/2008
  |  */
  | public final class HibernateCleaner
  | {
  | 	/**
  | 	 * Traverse through the object removing all fields of type 
  | 	 * org.hibernate.collection.PersistentCollection. by following all bean style get* methods.
  | 	 * <p>
  | 	 * <b>Note</b> the object cannot be reattached after calling this method.
  | 	 * 
  | 	 * @param obj the object to clean
  | 	 */
  | 	public static void clean(final Object obj)
  | 	{
  | 		try
  | 		{
  | 			removePersistenceContext(obj, new HashSet<Integer>());
  | 		}
  | 		catch (final IllegalAccessException e)
  | 		{
  | 			throw new RuntimeException(e);
  | 		}
  | 		catch (final InvocationTargetException e)
  | 		{
  | 			throw new RuntimeException(e);
  | 		}
  | 		catch (final NoSuchMethodException e)
  | 		{
  | 			throw new RuntimeException(e);
  | 		}
  | 	}
  | 
  | 	/**
  | 	 * Checks if the object MIGHT contain PersistentCollection fields by checking if its not a
  | 	 * primitive, or if its in package java.* or javax.*.
  | 	 * 
  | 	 * <p>
  | 	 * <b>NOTE</b> This relies on there not being an entity within those packages.
  | 	 * A more conservative approach is to only check if its a primitive.
  | 	 * @param obj the object to check
  | 	 * @author James Adams
  | 	 */
  | 	public static boolean couldObjectContainPersistentCollections(final Object obj)
  | 	{
  | 		if (obj == null) return false;
  | 
  | 		final Class clazz = obj.getClass();
  | 
  | 		if (clazz.isPrimitive()) return false;
  | 
  | 		final String className = clazz.getName();
  | 
  | 		//TODO - This is not fool proof and relies on people not using package with names below.
  | 		//More conservative approach is to remove this
  | 		if (className.startsWith("java.") || className.startsWith("javax.")) return false;
  | 
  | 		return true; //If we got here it might be a hibernate persisted object
  | 	}
  | 
  | 	/**
  | 	 * Because this class is in package org.hibernate.collection this method
  | 	 * allows us to access the inner protected fields of the hibernate collections
  | 	 * @param obj
  | 	 * @return The inner collection object of the PersistentCollection parameter
  | 	 * @author James Adams
  | 	 */
  | 	private static Object getInnerCollection(final PersistentCollection obj)
  | 	{
  | 		if (obj instanceof PersistentBag)
  | 			return ((PersistentBag) obj).bag;
  | 		else if (obj instanceof PersistentList)
  | 			return ((PersistentList) obj).list;
  | 		else if (obj instanceof PersistentSet)
  | 			return ((PersistentSet) obj).set;
  | 		else if (obj instanceof PersistentMap)
  | 			return ((PersistentMap) obj).map;
  | 		else if (obj instanceof PersistentSortedMap)
  | 			return ((PersistentSortedMap) obj).map;
  | 		else if (obj instanceof PersistentSortedSet)
  | 			return ((PersistentSortedSet) obj).set;
  | 		else
  | 			return null;
  | 	}
  | 
  | 	/**
  | 	 * If the specified object's identity hash code is not in the specified
  | 	 * collection of visited hash codes, removes of all data binding the object
  | 	 * (and its members) to a specific persistence context, leaving intact only
  | 	 * model-centric data
  | 	 * 
  | 	 * @param visitedObjectHashCodes
  | 	 * @param obj
  | 	 * @author ALR
  | 	 * @author James Adams, modified 6/9/2006,7/9/2006
  | 	 * @throws NoSuchMethodException 
  | 	 * @throws InvocationTargetException 
  | 	 * @throws IllegalAccessException 
  | 	 */
  | 	private static Object removePersistenceContext(Object obj, //
  | 			final Collection<Integer> visitedObjectHashCodes) //
  | 			throws IllegalAccessException, InvocationTargetException, NoSuchMethodException
  | 	{
  | 		if (obj == null) return null;
  | 
  | 		final Integer hashCode = System.identityHashCode(obj);
  | 
  | 		if (visitedObjectHashCodes.contains(hashCode)) return obj;
  | 
  | 		//Add the object's hash to the Collection of visited hash codes
  | 		visitedObjectHashCodes.add(hashCode);
  | 
  | 		try
  | 		{
  | 			// If runtime type of persistentCollection is PersistentCollection we get the
  | 			// inner collection from within the hibernate proxy
  | 			if (obj instanceof PersistentCollection)
  | 			{
  | 				obj = getInnerCollection((PersistentCollection) obj);
  | 			}
  | 		}
  | 		catch (final LazyInitializationException e)
  | 		{
  | 			return null;
  | 		}
  | 
  | 		if (obj == null) return null;
  | 
  | 		if (obj instanceof Collection)
  | 		{
  | 			for (final Object o : (Collection< ? >) obj)
  | 			{
  | 				//recurse into each element of the collection.  We don't need to set the value of 
  | 				//the object in the Collection as the reference will be adjusted, doing so within
  | 				//this iterable loop would result in a ConcurrentModificationException anyway. 
  | 				removePersistenceContext(o, visitedObjectHashCodes);
  | 				//TODO - Does Hibernate support Collections of primitives? As this will not work 
  | 				// when the Collection is of types that Java does not pass by reference;
  | 				// primitives, String, Integer, Float etc.
  | 				// In this case we need to create a new Collection and populate it. 
  | 			}
  | 		}
  | 		else if (!couldObjectContainPersistentCollections(obj))
  | 			return obj;
  | 		else
  | 		{
  | 			@SuppressWarnings("unchecked")
  | 			final Map<String, Object> allMembers = PropertyUtils.describe(obj);
  | 			for (final Map.Entry<String, Object> member : allMembers.entrySet())
  | 			{
  | 				final Object propertyValue = member.getValue();
  | 				try
  | 				{
  | 					final Object cleanedValue = removePersistenceContext(propertyValue, // 
  | 							visitedObjectHashCodes);
  | 
  | 					// avoid costly calls via reflection if the value has not been modified
  | 					if (cleanedValue != propertyValue)
  | 					{
  | 						PropertyUtils.setProperty(obj, member.getKey(), cleanedValue);
  | 					}
  | 				}
  | 				catch (final LazyInitializationException e)
  | 				{
  | 					PropertyUtils.setProperty(obj, member.getKey(), null);
  | 				}
  | 			}
  | 		}
  | 		return obj;
  | 	}
  | 
  | 	private HibernateCleaner()
  | 	{
  | 	// nothing
  | 	}
  | }

View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4162685#4162685

Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4162685



More information about the jboss-user mailing list