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

ALRubinger do-not-reply at jboss.com
Tue Sep 5 16:41:25 EDT 2006


Allright; I've got something.  Would love to hear opinions as to whether this makes for good design, and I'll probably cross-post this somewhere on the Hibernate forums to get thoughts from there...

Given a static utility method (code all below) that will return a non-Hibernate Collection of Entities, I had wanted to create a method that would strip out all Hibernate Collections from a POJO, like:

Object newPojo = PersistenceUtils.removePersistenceContext(myPojo);

...however, could not figure any intelligent way to instruct the method as to how deeply it should be traversing its own graph to look for Hibernate classes.

So I restructured a bit (this is the part on which I'm wavering) to place the Hibernate-stripping method in an assumed Base Class for all entities.  So the call now looks more like:

myPojo.removePersistenceContext();

I don't like that this solution requires a base entity class.

But it works for now - curious as to anyone's thoughts.

The Utility Class:

public class PersistenceUtils {
  | 
  | 	/**
  | 	 * Returns a Collection of all objects in the specified persistentCollection
  | 	 * without binding to any persistence context or session.
  | 	 * 
  | 	 * @param <T>
  | 	 * @param targetCollection
  | 	 * @param persistentCollection
  | 	 * @return
  | 	 */
  | 	public static <T> Collection<T> removeCollectionItemsFromPersistenceContext(
  | 			Collection<T> targetCollection, Collection<T> persistentCollection) {
  | 		// If runtime type of persistentCollection is not PersistentCollection,
  | 		// take no action
  | 		if (!(persistentCollection instanceof PersistentCollection))
  | 			return persistentCollection;
  | 
  | 		// Clear existing target
  | 		targetCollection.clear();
  | 
  | 		// Place all items in persistent collection into target
  | 		for (T item : persistentCollection) {
  | 			targetCollection.add(item);
  | 		}
  | 
  | 		// Return target
  | 		return targetCollection;
  | 	}
  | 
  | }
  | 


Base Entity Class (from which all EJB3 Entities inherit; relevent code only shown):

/**
  | 	 * Strips the entity of all data binding it to a specific persistence
  | 	 * context, leaving intact only model-centric data
  | 	 * 
  | 	 * @author ALR
  | 	 */
  | 	public void removePersistenceContext() {
  | 		// Initialize
  | 		Collection<Integer> visitedObjectHashCodes = new ArrayList<Integer>();
  | 
  | 		// Run
  | 		this.removePersistenceContext(this, visitedObjectHashCodes);
  | 	}
  | 
  | 	/**
  | 	 * 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
  | 	 */
  | 	private Object removePersistenceContext(Object obj,
  | 			Collection<Integer> visitedObjectHashCodes) {
  | 
  | 		// Ensure the current object has not been visited
  | 		if (visitedObjectHashCodes.contains(System.identityHashCode(obj))) {
  | 			return obj;
  | 		}
  | 
  | 		// Add the current object's hash to the Collection of visited hash codes
  | 		visitedObjectHashCodes.add(System.identityHashCode(obj));
  | 
  | 		// If the current object is of type Collection
  | 		if (Collection.class.isInstance(obj)) {
  | 			// Remove persistence context
  | 			obj = PersistenceUtils.removeCollectionItemsFromPersistenceContext(
  | 					new ArrayList(), (Collection) obj);
  | 		}
  | 
  | 		// Only traverse into types of PersistedEntity
  | 		if (!(PersistedEntity.class.isInstance(obj))) {
  | 			return obj;
  | 		}
  | 
  | 		// Remove persistence context of all members
  | 		Map allMembers = this.getInternalMembers();
  | 		for (Object member : allMembers.entrySet()) {
  | 			Map.Entry m = (Map.Entry) member;
  | 			try {
  | 				PropertyUtils.setProperty((Object) obj, m.getKey().toString(),
  | 						this.removePersistenceContext((m.getValue()),
  | 								visitedObjectHashCodes));
  | 			} catch (IllegalAccessException e) {
  | 				throw new RuntimeException(e);
  | 			} catch (InvocationTargetException e) {
  | 				throw new RuntimeException(e);
  | 			} catch (NoSuchMethodException e) {
  | 			}
  | 		}
  | 
  | 		// Return
  | 		return obj;
  | 	}
  | 
  | 	// Internal Helper Methods
  | 	/**
  | 	 * Returns a Map of all internal members of the specified object
  | 	 * 
  | 	 * @param obj
  | 	 *            The object for which to obtain internal members
  | 	 * 
  | 	 * @author ALR
  | 	 * @see http://jakarta.apache.org/commons/beanutils/
  | 	 */
  | 	protected Map getInternalMembers(PersistedEntity obj) {
  | 		try {
  | 			// Return a map of all visible properties
  | 			return PropertyUtils.describe(obj);
  | 		}
  | 		// Throw as unchecked exceptions up the stack trace
  | 		catch (IllegalAccessException iae) {
  | 			throw new RuntimeException(iae);
  | 		} catch (NoSuchMethodException nsme) {
  | 			throw new RuntimeException(nsme);
  | 		} catch (InvocationTargetException ite) {
  | 			throw new RuntimeException(ite);
  | 		}
  | 	}
  | 
  | 	/**
  | 	 * Returns a Map of all internal members of this PersistedEntitys
  | 	 * 
  | 	 * @author ALR
  | 	 * @see http://jakarta.apache.org/commons/beanutils/
  | 	 */
  | 	protected Map getInternalMembers() {
  | 		return getInternalMembers(this);
  | 	}

Easy to use (one line of code), and it works.  But I have the nagging feeling I can't be the first to have come across this, and there's a better way?

S,
ALR

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

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



More information about the jboss-user mailing list