History | Log In     View a printable version of the current page.  
Issue Details (XML | Word | Printable)

Key: HHH-2027
Type: Bug Bug
Status: Resolved Resolved
Resolution: Fixed
Priority: Major Major
Assignee: Steve Ebersole
Reporter: Josh Moore
Votes: 0
Watchers: 1
Operations

If you were logged in you would be able to see more operations.
Hibernate Core

merge listener over-writes Interceptor changes to component state for a transient entity

Created: 25/Aug/06 07:53 AM   Updated: 14/Nov/06 07:30 AM
Component/s: core
Affects Version/s: 3.2.0.cr2
Fix Version/s: 3.2.1

Time Tracking:
Not Specified

File Attachments: 1. Zip Archive nullcomponentinterceptor.zip (3 kb)

Environment:
Hibernate r10347
java version "1.5.0_07"
Issue Links:
Relates
 


 Description  « Hide
When an interceptor sets a previously null component-typed property of an entity to a non-null value, ComponentType.replace reverts the value to null due to the lines 422-425:

if ( original == null ) {
return null;
}

This means it is not possible on Interceptor.onSave() to "fix" a null component even if true is returned. Excerpts from the attached zip file follow:

[MAPPING]

<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="Details">
          <property name="perm1" not-null="true"
              type="long" column="permissions"/>
        </component>

<property name="name" type="java.lang.String" column="name" not-null="true" length="256"/>

</class>

[INTERCEPTOR]

public class DetailsInterceptor extends EmptyInterceptor {

boolean onSaveCalled = false;

@Override
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
state[0] = new Details();
onSaveCalled = true;
return true;
}

}

[TEST]

DetailsInterceptor pi = new DetailsInterceptor();

Session s = openSession( pi );
Transaction t = s.beginTransaction();
Image i = new Image();
i.setName("compincomp");

// the interceptor does the equivalent of:
//
// i.setDetails( new Details() );
//
// which when uncommented makes this test pass.
//
// without that line, the null details gets copied back to the result
// on merge causing the following on commit:
/*
org.hibernate.PropertyValueException: not-null property references a null or transient value: org.hibernate.test.compincomp.Image.details
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
at org.hibernate.event.def.DefaultFlushEntityEventListener.scheduleUpdate(DefaultFlushEntityEventListener.java:263)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:121)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:195)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:76)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
*/

s.merge(i);
assertTrue( pi.onSaveCalled );
t.commit();
s.close();

 All   Comments   Work Log   Change History   FishEye      Sort Order: Ascending order - Click to sort in descending order
Josh Moore - 25/Aug/06 07:55 AM
Had similar problems with "reseting" properties from an interceptor (see HHH-1921), though for a different reason. HHH-1921 has possibly been corrected.

Josh Moore - 25/Aug/06 07:59 AM
Is HHH-1907 related? EntityType also has a similar check, but perhaps the two currently function differently enough to cause the reversion.

Steve Ebersole - 10/Nov/06 09:32 PM
 Actually the real culprit here is DefaultMergeEventListener.entityIsTransient(). The save calls actually complete as anticipated *in terms of the managed copy state*, but the problem comes then from the after save cascading which writes the null component value from the original entity back into the managed copy, over-writing the work done by the interceptor during sve.

Just so I dont forget when I get a chance to get back to this ;)

Steve Ebersole - 10/Nov/06 09:53 PM
Actually, this is easy...

On that second call, only perform the replace on associations. Value types (strings, components, etc) have already been replaced correctly during the first pass. Replacing them (again) on the second pass:
(1) is redundant
(2) causes this problem ;)

Steve Ebersole - 10/Nov/06 11:14 PM
org.hibernate.test.interceptor.InterceptorTest#testComponentInterceptor