We're updating the issue view to help you get more done. 

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

Description

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;
assertTrue( pi.onSaveCalled );
t.commit();
s.close();

Environment

Hibernate r10347 java version "1.5.0_07"

Status

Assignee

Steve Ebersole

Reporter

Josh Moore

Components

Fix versions

Affects versions

3.2.0.cr2

Priority

Major