[hibernate-commits] Hibernate SVN: r19604 - in core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb: util and 1 other directory.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue May 25 09:31:51 EDT 2010


Author: epbernard
Date: 2010-05-25 09:31:50 -0400 (Tue, 25 May 2010)
New Revision: 19604

Modified:
   core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/EntityManagerFactoryImpl.java
   core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/HibernatePersistence.java
   core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/util/PersistenceUtilHelper.java
Log:
HHH-5258 isLoaded and superclasses and private properties now works

Use getDeclaredField and getDeclaredMethod, use the whole class hierarchy
and use a cache to speed up both class hierarchy
and property to Member computation

Modified: core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/EntityManagerFactoryImpl.java
===================================================================
--- core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/EntityManagerFactoryImpl.java	2010-05-25 13:31:08 UTC (rev 19603)
+++ core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/EntityManagerFactoryImpl.java	2010-05-25 13:31:50 UTC (rev 19604)
@@ -65,6 +65,7 @@
 	private final Metamodel metamodel;
 	private final HibernatePersistenceUnitUtil util;
 	private final Map<String,Object> properties;
+	private final PersistenceUtilHelper.MetadataCache cache = new PersistenceUtilHelper.MetadataCache();
 
 	@SuppressWarnings( "unchecked" )
 	public EntityManagerFactoryImpl(
@@ -182,13 +183,15 @@
 
 	private static class HibernatePersistenceUnitUtil implements PersistenceUnitUtil, Serializable {
 		private final HibernateEntityManagerFactory emf;
+		private transient PersistenceUtilHelper.MetadataCache cache;
 
 		private HibernatePersistenceUnitUtil(EntityManagerFactoryImpl emf) {
 			this.emf = emf;
+			this.cache = emf.cache;
 		}
 
 		public boolean isLoaded(Object entity, String attributeName) {
-			LoadState state = PersistenceUtilHelper.isLoadedWithoutReference( entity, attributeName );
+			LoadState state = PersistenceUtilHelper.isLoadedWithoutReference( entity, attributeName, cache );
 			if (state == LoadState.LOADED) {
 				return true;
 			}
@@ -196,7 +199,7 @@
 				return false;
 			}
 			else {
-				return PersistenceUtilHelper.isLoadedWithReference( entity, attributeName ) != LoadState.NOT_LOADED;
+				return PersistenceUtilHelper.isLoadedWithReference( entity, attributeName, cache ) != LoadState.NOT_LOADED;
 			}
 		}
 

Modified: core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/HibernatePersistence.java
===================================================================
--- core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/HibernatePersistence.java	2010-05-25 13:31:08 UTC (rev 19603)
+++ core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/HibernatePersistence.java	2010-05-25 13:31:50 UTC (rev 19604)
@@ -38,6 +38,7 @@
  * @author Gavin King
  */
 public class HibernatePersistence extends AvailableSettings implements PersistenceProvider {
+	private final PersistenceUtilHelper.MetadataCache cache = new PersistenceUtilHelper.MetadataCache();
 
 	/**
 	 * Get an entity manager factory by its entity manager name, using the specified
@@ -85,11 +86,11 @@
 
 	private final ProviderUtil providerUtil = new ProviderUtil() {
 		public LoadState isLoadedWithoutReference(Object proxy, String property) {
-			return PersistenceUtilHelper.isLoadedWithoutReference( proxy, property );
+			return PersistenceUtilHelper.isLoadedWithoutReference( proxy, property, cache );
 		}
 
 		public LoadState isLoadedWithReference(Object proxy, String property) {
-			return PersistenceUtilHelper.isLoadedWithReference( proxy, property );
+			return PersistenceUtilHelper.isLoadedWithReference( proxy, property, cache );
 		}
 
 		public LoadState isLoaded(Object o) {

Modified: core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/util/PersistenceUtilHelper.java
===================================================================
--- core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/util/PersistenceUtilHelper.java	2010-05-25 13:31:08 UTC (rev 19603)
+++ core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/util/PersistenceUtilHelper.java	2010-05-25 13:31:50 UTC (rev 19604)
@@ -1,14 +1,21 @@
 package org.hibernate.ejb.util;
 
+import java.io.Serializable;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Member;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.AccessibleObject;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
 import javax.persistence.spi.LoadState;
 import javax.persistence.PersistenceException;
 
+import org.hibernate.AssertionFailure;
 import org.hibernate.proxy.HibernateProxy;
 import org.hibernate.proxy.LazyInitializer;
 import org.hibernate.intercept.FieldInterceptionHelper;
@@ -19,7 +26,7 @@
  * @author Emmanuel Bernard
  */
 public class PersistenceUtilHelper {
-	public static LoadState isLoadedWithoutReference(Object proxy, String property) {
+	public static LoadState isLoadedWithoutReference(Object proxy, String property, MetadataCache cache) {
 		Object entity;
 		boolean sureFromUs = false;
 		if ( proxy instanceof HibernateProxy ) {
@@ -44,7 +51,7 @@
 			if (isInitialized && interceptor != null) {
 				//property is loaded according to bytecode enhancement, but is it loaded as far as association?
 				//it's ours, we can read
-				state = isLoaded( get( entity, property ) );
+				state = isLoaded( get( entity, property, cache ) );
 				//it's ours so we know it's loaded
 				if (state == LoadState.UNKNOWN) state = LoadState.LOADED;
 			}
@@ -54,7 +61,7 @@
 			else if ( sureFromUs ) { //interceptor == null
 				//property is loaded according to bytecode enhancement, but is it loaded as far as association?
 				//it's ours, we can read
-				state = isLoaded( get( entity, property ) );
+				state = isLoaded( get( entity, property, cache ) );
 				//it's ours so we know it's loaded
 				if (state == LoadState.UNKNOWN) state = LoadState.LOADED;
 			}
@@ -71,32 +78,26 @@
 		}
 	}
 
-	public static LoadState isLoadedWithReference(Object proxy, String property) {
+	public static LoadState isLoadedWithReference(Object proxy, String property, MetadataCache cache) {
 		//for sure we don't instrument and for sure it's not a lazy proxy
-		Object object = get(proxy, property);
+		Object object = get(proxy, property, cache);
 		return isLoaded( object );
 	}
 
-	private static Object get(Object proxy, String property) {
+	private static Object get(Object proxy, String property, MetadataCache cache) {
 		final Class<?> clazz = proxy.getClass();
+
 		try {
-			try {
-				final Field field = clazz.getField( property );
-				setAccessibility( field );
-				return field.get( proxy );
+			Member member = cache.getMember( clazz, property );
+			if (member instanceof Field) {
+				return ( (Field) member ).get( proxy );
 			}
-			catch ( NoSuchFieldException e ) {
-				final Method method = getMethod( clazz, property );
-				if (method != null) {
-					setAccessibility( method );
-					return method.invoke( proxy );
-				}
-				else {
-					throw new PersistenceException( "Unable to find field or method: "
-							+ clazz + "#"
-							+ property);
-				}
+			else if (member instanceof Method) {
+				return ( (Method) member ).invoke( proxy );
 			}
+			else {
+				throw new AssertionFailure( "Member object neither Field nor Method: " + member);
+			}
 		}
 		catch ( IllegalAccessException e ) {
 			throw new PersistenceException( "Unable to access field or method: "
@@ -110,6 +111,27 @@
 		}
 	}
 
+	private static void setAccessibility(Member member) {
+		if ( !Modifier.isPublic( member.getModifiers() ) ) {
+			//Sun's ease of use, sigh...
+			( ( AccessibleObject ) member ).setAccessible( true );
+		}
+	}
+
+	public static LoadState isLoaded(Object o) {
+		if ( o instanceof HibernateProxy ) {
+			final boolean isInitialized = !( ( HibernateProxy ) o ).getHibernateLazyInitializer().isUninitialized();
+			return isInitialized ? LoadState.LOADED : LoadState.NOT_LOADED;
+		}
+		else if ( o instanceof PersistentCollection ) {
+			final boolean isInitialized = ( ( PersistentCollection ) o ).wasInitialized();
+			return isInitialized ? LoadState.LOADED : LoadState.NOT_LOADED;
+		}
+		else {
+			return LoadState.UNKNOWN;
+		}
+	}
+
 	/**
 	 * Returns the method with the specified name or <code>null</code> if it does not exist.
 	 *
@@ -135,25 +157,84 @@
 		}
 	}
 
-	private static void setAccessibility(Member member) {
-		if ( !Modifier.isPublic( member.getModifiers() ) ) {
-			//Sun's ease of use, sigh...
-			( ( AccessibleObject ) member ).setAccessible( true );
+	/**
+	 * Cache hierarchy and member resolution in a weak hash map
+	 */
+	//TODO not really thread-safe
+	public static class MetadataCache implements Serializable {
+		private transient Map<Class<?>, ClassCache> classCache = new WeakHashMap<Class<?>, ClassCache>();
+
+
+		private void readObject(java.io.ObjectInputStream stream) {
+			classCache = new WeakHashMap<Class<?>, ClassCache>();
 		}
-	}
 
-	public static LoadState isLoaded(Object o) {
-		if ( o instanceof HibernateProxy ) {
-			final boolean isInitialized = !( ( HibernateProxy ) o ).getHibernateLazyInitializer().isUninitialized();
-			return isInitialized ? LoadState.LOADED : LoadState.NOT_LOADED;
+		Member getMember(Class<?> clazz, String property) {
+			ClassCache cache = classCache.get( clazz );
+			if (cache == null) {
+				cache = new ClassCache(clazz);
+				classCache.put( clazz, cache );
+			}
+			Member member = cache.members.get( property );
+			if ( member == null ) {
+				member = findMember( clazz, property );
+				cache.members.put( property, member );
+			}
+			return member;
 		}
-		else if ( o instanceof PersistentCollection ) {
-			final boolean isInitialized = ( ( PersistentCollection ) o ).wasInitialized();
-			return isInitialized ? LoadState.LOADED : LoadState.NOT_LOADED;
+
+		private Member findMember(Class<?> clazz, String property) {
+			final List<Class<?>> classes = getClassHierarchy( clazz );
+
+			for (Class current : classes) {
+				final Field field;
+				try {
+					field = current.getDeclaredField( property );
+					setAccessibility( field );
+					return field;
+				}
+				catch ( NoSuchFieldException e ) {
+					final Method method = getMethod( clazz, property );
+					if (method != null) {
+						setAccessibility( method );
+						return method;
+					}
+				}
+			}
+			//we could not find any match
+			throw new PersistenceException( "Unable to find field or method: "
+							+ clazz + "#"
+							+ property);
 		}
-		else {
-			return LoadState.UNKNOWN;
+
+		private List<Class<?>> getClassHierarchy(Class<?> clazz) {
+			ClassCache cache = classCache.get( clazz );
+			if (cache == null) {
+				cache = new ClassCache(clazz);
+				classCache.put( clazz, cache );
+			}
+			return cache.classHierarchy;
 		}
+
+		private static List<Class<?>> findClassHierarchy(Class<?> clazz) {
+			List<Class<?>> classes = new ArrayList<Class<?>>();
+			Class<?> current = clazz;
+			do {
+				classes.add( current );
+				current = current.getSuperclass();
+			}
+			while ( current != null );
+			return classes;
+		}
+
+		private static class ClassCache {
+			List<Class<?>> classHierarchy;
+			Map<String, Member> members = new HashMap<String, Member>();
+
+			public ClassCache(Class<?> clazz) {
+				classHierarchy = findClassHierarchy( clazz );
+			}
+		}
 	}
 
 }



More information about the hibernate-commits mailing list