Author: steve.ebersole(a)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() {