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

Fix versions

Labels

None

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Components

Affects versions

3.2.0.cr2

Priority

Major