Author: steve.ebersole(a)jboss.com
Date: 2006-11-11 00:12:37 -0500 (Sat, 11 Nov 2006)
New Revision: 10783
Added:
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/interceptor/Image.hbm.xml
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/interceptor/Image.java
Modified:
branches/Branch_3_2/Hibernate3/src/org/hibernate/event/def/DefaultFlushEntityEventListener.java
branches/Branch_3_2/Hibernate3/src/org/hibernate/event/def/DefaultMergeEventListener.java
branches/Branch_3_2/Hibernate3/src/org/hibernate/type/TypeFactory.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/interceptor/InterceptorTest.java
Log:
HHH-1921 & HHH-2027: interceptor/listener changing properties
Modified:
branches/Branch_3_2/Hibernate3/src/org/hibernate/event/def/DefaultFlushEntityEventListener.java
===================================================================
---
branches/Branch_3_2/Hibernate3/src/org/hibernate/event/def/DefaultFlushEntityEventListener.java 2006-11-11
04:27:51 UTC (rev 10782)
+++
branches/Branch_3_2/Hibernate3/src/org/hibernate/event/def/DefaultFlushEntityEventListener.java 2006-11-11
05:12:37 UTC (rev 10783)
@@ -232,16 +232,16 @@
);
}
}
+
+ boolean intercepted;
- boolean substitute;
-
if ( !entry.isBeingReplicated() ) {
// 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 +251,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 +280,7 @@
)
);
- return substitute;
+ return intercepted;
}
protected void validate(Object entity, EntityPersister persister, Status status,
EntityMode entityMode) {
@@ -320,17 +320,15 @@
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:
branches/Branch_3_2/Hibernate3/src/org/hibernate/event/def/DefaultMergeEventListener.java
===================================================================
---
branches/Branch_3_2/Hibernate3/src/org/hibernate/event/def/DefaultMergeEventListener.java 2006-11-11
04:27:51 UTC (rev 10782)
+++
branches/Branch_3_2/Hibernate3/src/org/hibernate/event/def/DefaultMergeEventListener.java 2006-11-11
05:12:37 UTC (rev 10783)
@@ -172,7 +172,7 @@
final Object copy = persister.instantiate( id, source.getEntityMode() ); //TODO:
should this be Session.instantiate(Persister, ...)?
copyCache.put(entity, copy); //before cascade!
- // cascade first, so that all unsaved objects get their
+ // cascade first, so that all unsaved objects get their
// copy created before we actually copy
//cascadeOnMerge(event, persister, entity, copyCache, Cascades.CASCADE_BEFORE_MERGE);
super.cascadeBeforeSave(source, persister, entity, copyCache);
@@ -350,27 +350,44 @@
}
protected void copyValues(
- final EntityPersister persister,
+ 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: branches/Branch_3_2/Hibernate3/src/org/hibernate/type/TypeFactory.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/type/TypeFactory.java 2006-11-11
04:27:51 UTC (rev 10782)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/type/TypeFactory.java 2006-11-11
05:12:37 UTC (rev 10783)
@@ -498,6 +498,40 @@
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;
+ }
/**
Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/interceptor/Image.hbm.xml
===================================================================
---
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/interceptor/Image.hbm.xml 2006-11-11
04:27:51 UTC (rev 10782)
+++
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/interceptor/Image.hbm.xml 2006-11-11
05:12:37 UTC (rev 10783)
@@ -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: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/interceptor/Image.java
===================================================================
---
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/interceptor/Image.java 2006-11-11
04:27:51 UTC (rev 10782)
+++
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/interceptor/Image.java 2006-11-11
05:12:37 UTC (rev 10783)
@@ -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:
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/interceptor/InterceptorTest.java
===================================================================
---
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/interceptor/InterceptorTest.java 2006-11-11
04:27:51 UTC (rev 10782)
+++
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/interceptor/InterceptorTest.java 2006-11-11
05:12:37 UTC (rev 10783)
@@ -2,12 +2,15 @@
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;
/**
@@ -54,8 +57,83 @@
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 );
@@ -79,7 +157,7 @@
}
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() {