ManyToOneType.isDirty

Description

public boolean isDirty(
Object old,
Object current,
SessionImplementor session) throws HibernateException {
if ( isSame( old, current ) )
{ return false; }
Object oldid = getIdentifier( old, session );
Object newid = getIdentifier( current, session );
return getIdentifierType( session ).isDirty( oldid, newid, session );
}
return getIdentifierType( session ).isDirty( oldid, newid, session );
==>
return getIdentifierOrUniqueKeyType( session ).isDirty( oldid, newid, session );

for property-ref in xml
getIdentifierType( session ) return identity type of the associated entity
instead of what the property-ref property type is expected

ADD:
Object oldid = getIdentifier( old, session );
Object newid = getIdentifier( current, session );
getIdentifier() process the property-ref perfectly

previous issue:
https://hibernate.atlassian.net/browse/HHH-9335

hbm.xml:
Person
<class entity-name="O2O_Person" table="ONE_TO_ONE_PERSON">
<id name="id" type="java.math.BigDecimal">
<column name="ID" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<many-to-one name="address" entity-name="O2O_Address" property-ref="fk" cascade="save-update" unique="true">
<column name="ADDRESS_ID" ></column>
</many-to-one>
</class>
Address
<class entity-name="O2O_Address" table="ONE_TO_ONE_ADDRESS">
<id name="id" type="java.math.BigDecimal">
<column name="ID" />
</id>
<property name="addressName" type="java.lang.String">
<column name="NAME" />
</property>
</class>

exception:
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to java.math.BigDecimal
at org.hibernate.type.descriptor.java.BigDecimalTypeDescriptor.areEqual(BigDecimalTypeDescriptor.java:36)
at org.hibernate.type.AbstractStandardBasicType.isEqual(AbstractStandardBasicType.java:207)
at org.hibernate.type.AbstractStandardBasicType.isSame(AbstractStandardBasicType.java:197)
at org.hibernate.type.AbstractStandardBasicType.isDirty(AbstractStandardBasicType.java:233)
at org.hibernate.type.AbstractStandardBasicType.isDirty(AbstractStandardBasicType.java:225)
at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:312)
at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:321)
at org.hibernate.type.TypeHelper.findDirty(TypeHelper.java:294)
at org.hibernate.persister.entity.AbstractEntityPersister.findDirty(AbstractEntityPersister.java:4237)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.dirtyCheck(DefaultFlushEntityEventListener.java:546)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.isUpdateNecessary(DefaultFlushEntityEventListener.java:232)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:159)

Very Important:
this exception occurred only when the identifier type of the associated entity is BigDecimal(and other type which's TypeDescriptor override the "areEquals" method of AbstractTypeDescriptor)

Environment

h 4.3.5
oracle 11gr2

Activity

Show:
Gail Badner
October 24, 2017, 9:39 PM

indicates that this is not broken using hbm.xml, but maybe this is related.

Steve Ebersole
October 24, 2017, 10:04 PM

if you are willing to take a look at a fix, that would be awesome

Steve Ebersole
October 25, 2017, 2:01 PM

We can only assign issues to certain people. That role allows elevated privileges that we only want to attribute to frequent contributors. But all of us will see the conversation here - we will know you are working on it.

As far as guidelines, well per convetion that is all outlined in the project's README
and CONTRIBUTING files located in the repo:

Andy Zhao
October 25, 2017, 6:34 PM

Here is my analysis of the problem in my specific use case mentioned above. But I want to say that both Address and Country object, as well as the many-to-one property was used in Hibernate 3.x and without any issue.

Below are some details about the stack trace:
1. org.hibernate.persister.entity.AbstractEntityPersister.finDirty was called and the static TypeHelper.findDirty comes to the play;

2. the map-to-one element was loaded as a NonIdentifierAttribute object:
org.hibernate.type.TypeHelper.findDirty: property is {Attribute(name=countryObject, type=lookup.Country [non-identifier,association])}

3. A call of properties[i].getType() determines that is a MapToOneType, the isDirty calls to getIdentifierType(seesion) to determine the type of the identity of this associationtype, which is BigDecimal on lookup.Country

4. Since the join is not on the identity as usually do for associations the "property-ref" value is a String the cast to BigDecimal throws an Exception.
Make sense?

Andy Zhao
October 25, 2017, 6:51 PM

Need to mention that on ManyToOneType there are two versions of isDirty, one with a list of checkable, which calls the second version if
isAlwaysDirtyChecked is true, which is always true in the implementation!

Assignee

Unassigned

Reporter

xinhuil

Fix versions

None

backPortable

None

Suitable for new contributors

Yes, likely

Requires Release Note

Affirmative

Pull Request

None

backportDecision

None

Components

Affects versions

Priority

Major
Configure