[hibernate-commits] Hibernate SVN: r10784 - in trunk/Hibernate3: src/org/hibernate/event/def src/org/hibernate/type test/org/hibernate/test/interceptor

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Sat Nov 11 00:13:07 EST 2006


Author: steve.ebersole at jboss.com
Date: 2006-11-11 00:13:01 -0500 (Sat, 11 Nov 2006)
New Revision: 10784

Added:
   trunk/Hibernate3/test/org/hibernate/test/interceptor/Image.hbm.xml
   trunk/Hibernate3/test/org/hibernate/test/interceptor/Image.java
Modified:
   trunk/Hibernate3/src/org/hibernate/event/def/DefaultFlushEntityEventListener.java
   trunk/Hibernate3/src/org/hibernate/event/def/DefaultMergeEventListener.java
   trunk/Hibernate3/src/org/hibernate/type/TypeFactory.java
   trunk/Hibernate3/test/org/hibernate/test/interceptor/InterceptorTest.java
Log:
HHH-1921 & HHH-2027: interceptor/listener changing  properties

Modified: trunk/Hibernate3/src/org/hibernate/event/def/DefaultFlushEntityEventListener.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/event/def/DefaultFlushEntityEventListener.java	2006-11-11 05:12:37 UTC (rev 10783)
+++ trunk/Hibernate3/src/org/hibernate/event/def/DefaultFlushEntityEventListener.java	2006-11-11 05:13:01 UTC (rev 10784)
@@ -232,16 +232,15 @@
 					);
 			}
 		}
-		
-		boolean substitute;
-		
+
+		final boolean intercepted;
 		if ( !entry.isBeingReplicated() ) {
-			// give the Interceptor a chance to process property values, if the properties 
+			// give the Interceptor a chance to process property values, if the properties
 			// were modified by the Interceptor, we need to set them back to the object
-			substitute = handleInterception(event);
+			intercepted = handleInterception( event );
 		}
 		else {
-			substitute = false;
+			intercepted = false;
 		}
 
 		validate( entity, persister, status, entityMode );
@@ -251,9 +250,9 @@
 
 		// if it was dirtied by a collection only
 		int[] dirtyProperties = event.getDirtyProperties();
-		if ( event.isDirtyCheckPossible() && dirtyProperties==null ) {
-			if ( !event.hasDirtyCollection() ) {
-				throw new AssertionFailure("dirty, but no dirty properties");
+		if ( event.isDirtyCheckPossible() && dirtyProperties == null ) {
+			if ( ! intercepted && !event.hasDirtyCollection() ) {
+				throw new AssertionFailure( "dirty, but no dirty properties" );
 			}
 			dirtyProperties = ArrayHelper.EMPTY_INT_ARRAY;
 		}
@@ -280,7 +279,7 @@
 					)
 			);
 		
-		return substitute;
+		return intercepted;
 	}
 
 	protected void validate(Object entity, EntityPersister persister, Status status, EntityMode entityMode) {
@@ -316,21 +315,19 @@
 	}
 
 	protected boolean invokeInterceptor(
-			SessionImplementor session, 
-			Object entity, 
-			EntityEntry entry, 
+			SessionImplementor session,
+			Object entity,
+			EntityEntry entry,
 			final Object[] values,
-			EntityPersister persister
-	) {
-		final boolean intercepted = session.getInterceptor().onFlushDirty(
+			EntityPersister persister) {
+		return session.getInterceptor().onFlushDirty(
 				entity,
 				entry.getId(),
 				values,
 				entry.getLoadedState(),
 				persister.getPropertyNames(),
 				persister.getPropertyTypes()
-			);
-		return intercepted;
+		);
 	}
 
 	/**

Modified: trunk/Hibernate3/src/org/hibernate/event/def/DefaultMergeEventListener.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/event/def/DefaultMergeEventListener.java	2006-11-11 05:12:37 UTC (rev 10783)
+++ trunk/Hibernate3/src/org/hibernate/event/def/DefaultMergeEventListener.java	2006-11-11 05:13:01 UTC (rev 10784)
@@ -352,27 +352,44 @@
 	}
 
 	protected void copyValues(
-			final EntityPersister persister, 
-			final Object entity, 
-			final Object target, 
+			final EntityPersister persister,
+			final Object entity,
+			final Object target,
 			final SessionImplementor source,
 			final Map copyCache,
-			final ForeignKeyDirection foreignKeyDirection
-		) {
-			
-			final Object[] copiedValues = TypeFactory.replace(
+			final ForeignKeyDirection foreignKeyDirection) {
+
+		final Object[] copiedValues;
+
+		if ( foreignKeyDirection == ForeignKeyDirection.FOREIGN_KEY_TO_PARENT ) {
+			// this is the second pass through on a merge op, so here we limit the
+			// replacement to associations types (value types were already replaced
+			// during the first pass)
+			copiedValues = TypeFactory.replaceAssociations(
 					persister.getPropertyValues( entity, source.getEntityMode() ),
 					persister.getPropertyValues( target, source.getEntityMode() ),
 					persister.getPropertyTypes(),
 					source,
-					target, 
+					target,
 					copyCache,
 					foreignKeyDirection
-				);
-
-			persister.setPropertyValues( target, copiedValues, source.getEntityMode() );
+			);
 		}
+		else {
+			copiedValues = TypeFactory.replace(
+					persister.getPropertyValues( entity, source.getEntityMode() ),
+					persister.getPropertyValues( target, source.getEntityMode() ),
+					persister.getPropertyTypes(),
+					source,
+					target,
+					copyCache,
+					foreignKeyDirection
+			);
+		}
 
+		persister.setPropertyValues( target, copiedValues, source.getEntityMode() );
+	}
+
 	/** 
 	 * Perform any cascades needed as part of this copy event.
 	 *

Modified: trunk/Hibernate3/src/org/hibernate/type/TypeFactory.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/type/TypeFactory.java	2006-11-11 05:12:37 UTC (rev 10783)
+++ trunk/Hibernate3/src/org/hibernate/type/TypeFactory.java	2006-11-11 05:13:01 UTC (rev 10784)
@@ -498,8 +498,43 @@
 		return copied;
 	}
 
+	/**
+	 * Apply the {@link Type#replace} operation across a series of values, as
+	 * long as the corresponding {@link Type} is an association.
+	 *
+	 * @param original The source of the state
+	 * @param target The target into which to replace the source values.
+	 * @param types The value types
+	 * @param session The orginating session
+	 * @param owner The entity "owning" the values
+	 * @param copyCache A map representing a cache of already replaced state
+	 * @param foreignKeyDirection FK directionality to be applied to the replacement
+	 * @return The replaced state
+	 */
+	public static Object[] replaceAssociations(
+			final Object[] original,
+			final Object[] target,
+			final Type[] types,
+			final SessionImplementor session,
+			final Object owner,
+			final Map copyCache,
+			final ForeignKeyDirection foreignKeyDirection) {
+		Object[] copied = new Object[original.length];
+		for ( int i = 0; i < types.length; i++ ) {
+			if ( original[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY
+					|| original[i] == BackrefPropertyAccessor.UNKNOWN
+					|| !types[i].isAssociationType() ) {
+				copied[i] = target[i];
+			}
+			else {
+				copied[i] = types[i].replace( original[i], target[i], session, owner, copyCache, foreignKeyDirection );
+			}
+		}
+		return copied;
+	}
 
 
+
 	/**
 	 * Determine if any of the given field values are dirty, returning an array containing
 	 * indices of the dirty fields.

Added: trunk/Hibernate3/test/org/hibernate/test/interceptor/Image.hbm.xml
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/interceptor/Image.hbm.xml	2006-11-11 05:12:37 UTC (rev 10783)
+++ trunk/Hibernate3/test/org/hibernate/test/interceptor/Image.hbm.xml	2006-11-11 05:13:01 UTC (rev 10784)
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.interceptor">
+
+    <class name="Image" table="image" abstract="false" select-before-update="true" >
+        <id name="id" type="java.lang.Long" column="id">
+            <generator class="native"/>
+        </id>
+        <component name="details" class="Image$Details">
+            <property name="perm1" not-null="true" type="long" column="permissions"/>
+            <property name="comment" type="string" column="comment_txt"/>
+        </component>
+        <property name="name" type="java.lang.String" column="name" not-null="true"/>
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/test/org/hibernate/test/interceptor/Image.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/interceptor/Image.java	2006-11-11 05:12:37 UTC (rev 10783)
+++ trunk/Hibernate3/test/org/hibernate/test/interceptor/Image.java	2006-11-11 05:13:01 UTC (rev 10784)
@@ -0,0 +1,63 @@
+package org.hibernate.test.interceptor;
+
+public class Image {
+
+	private Long id;
+	private String name;
+	private Details details;
+
+	public Details getDetails() {
+		return details;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setDetails(Details details) {
+		this.details = details;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String toString() {
+		return "Image/" + ( details == null ? "no details" : details.toString() );
+	}
+
+	public static class Details {
+		private long perm1 = -1; // all bits turned on.
+		private String comment;
+
+		protected long getPerm1() {
+			return this.perm1;
+		}
+
+		protected void setPerm1(long value) {
+			this.perm1 = value;
+		}
+
+		public String getComment() {
+			return comment;
+		}
+
+		public void setComment(String comment) {
+			this.comment = comment;
+		}
+
+		public String toString() {
+			return "Details=" + perm1;
+		}
+	}
+
+}
+

Modified: trunk/Hibernate3/test/org/hibernate/test/interceptor/InterceptorTest.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/interceptor/InterceptorTest.java	2006-11-11 05:12:37 UTC (rev 10783)
+++ trunk/Hibernate3/test/org/hibernate/test/interceptor/InterceptorTest.java	2006-11-11 05:13:01 UTC (rev 10784)
@@ -2,19 +2,22 @@
 package org.hibernate.test.interceptor;
 
 import java.util.List;
+import java.io.Serializable;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
 import org.hibernate.Session;
 import org.hibernate.Transaction;
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.type.Type;
 import org.hibernate.test.TestCase;
 
 /**
  * @author Gavin King
  */
 public class InterceptorTest extends TestCase {
-	
+
 	public InterceptorTest(String str) {
 		super(str);
 	}
@@ -27,7 +30,7 @@
 		u.setPassword("vagni");
 		t.commit();
 		s.close();
-		
+
 		s = openSession();
 		t = s.beginTransaction();
 		u = (User) s.get(User.class, "Gavin");
@@ -35,8 +38,8 @@
 		s.delete(u);
 		t.commit();
 		s.close();
-	}	
-	
+	}
+
 	public void testPropertyIntercept() {
 		Session s = openSession( new PropertyInterceptor() );
 		Transaction t = s.beginTransaction();
@@ -45,7 +48,7 @@
 		u.setPassword("vagni");
 		t.commit();
 		s.close();
-		
+
 		s = openSession();
 		t = s.beginTransaction();
 		u = (User) s.get(User.class, "Gavin");
@@ -54,20 +57,95 @@
 		s.delete(u);
 		t.commit();
 		s.close();
-	}	
-	
+	}
+
+	/**
+	 * Test case from HHH-1921.  Here the interceptor resets the
+	 * current-state to the same thing as the current db state; this
+	 * causes EntityPersister.findDirty() to return no dirty properties.
+	 */
+	public void testPropertyIntercept2() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User u = new User("Josh", "test");
+		s.persist( u );
+		t.commit();
+		s.close();
+
+		s = openSession(
+				new EmptyInterceptor() {
+					public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
+						currentState[0] = "test";
+						return true;
+					}
+				}
+		);
+		t = s.beginTransaction();
+		u = ( User ) s.get( User.class, u.getName() );
+		u.setPassword( "nottest" );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		u = (User) s.get(User.class, "Josh");
+		assertEquals("test", u.getPassword());
+		s.delete(u);
+		t.commit();
+		s.close();
+
+	}
+
+	public void testComponentInterceptor() {
+		final int checkPerm = 500;
+		final String checkComment = "generated from interceptor";
+
+		Session s = openSession(
+				new EmptyInterceptor() {
+					public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
+						if ( state[0] == null ) {
+							Image.Details detail = new Image.Details();
+							detail.setPerm1( checkPerm );
+							detail.setComment( checkComment );
+							state[0] = detail;
+						}
+						return true;
+					}
+				}
+		);
+		s.beginTransaction();
+		Image i = new Image();
+		i.setName( "compincomp" );
+		i = ( Image ) s.merge( i );
+		assertNotNull( i.getDetails() );
+		assertEquals( checkPerm, i.getDetails().getPerm1() );
+		assertEquals( checkComment, i.getDetails().getComment() );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		i = ( Image ) s.get( Image.class, i.getId() );
+		assertNotNull( i.getDetails() );
+		assertEquals( checkPerm, i.getDetails().getPerm1() );
+		assertEquals( checkComment, i.getDetails().getComment() );
+		s.delete( i );
+		s.getTransaction().commit();
+		s.close();
+	}
+
 	public void testStatefulIntercept() {
 		final StatefulInterceptor statefulInterceptor = new StatefulInterceptor();
 		Session s = openSession( statefulInterceptor );
 		statefulInterceptor.setSession(s);
-		
+
 		Transaction t = s.beginTransaction();
 		User u = new User("Gavin", "nivag");
 		s.persist(u);
 		u.setPassword("vagni");
 		t.commit();
 		s.close();
-		
+
 		s = openSession();
 		t = s.beginTransaction();
 		List logs = s.createCriteria(Log.class).list();
@@ -77,9 +155,9 @@
 		t.commit();
 		s.close();
 	}
-	
+
 	protected String[] getMappings() {
-		return new String[] { "interceptor/User.hbm.xml" };
+		return new String[] { "interceptor/User.hbm.xml", "interceptor/Image.hbm.xml" };
 	}
 
 	public static Test suite() {




More information about the hibernate-commits mailing list