Embeddable with a primitive field cannot be set to null

Description

Hibernate behaviour changed from version 6.2.7 to 6.2.8 so that existing code breaks. The change is quite annoying, as Hibernate 6.2.9 is included in Spring Boot v3.1.4, and I did not expect such a behaviour change with a patch version update.

Problem 1: JpaSystemException: Null value was assigned to a property

Assume the following entity:

@Entity data class EntityA( @Id val entityId: String, @AttributeOverrides( AttributeOverride(name = "amount", column = Column(name = "materialCost_amount")), AttributeOverride(name = "currency", column = Column(name = "materialCost_currency")), ) @Embedded val materialCost: Cost? = null, ) @Embeddable @Access(AccessType.FIELD) data class Cost( val amount: Int, val currency: String, ) @Repository interface EntityARepository : JpaRepository<EntityA, String>

With v6.2.7 we could save and update the entity as follows:

// initial save val fixture = EntityA( entityId = "id1", materialCost = Cost(20, "USD") ) val saved = repositoryA.save(fixture) // update val fixtureNoCosts = EntityA( entityId = "id1", materialCost = null ) val updated = repositoryA.save(fixtureNoCosts)

With v6.2.8 the last save throws org.springframework.orm.jpa.JpaSystemException: Null value was assigned to a property [class com.example.demo.Cost.amount] of primitive type : com.example.demo.Cost.amount (setter)

 

Problem 2: Nullable @Embedded object handled as expected

Building on the above example, assume the following entity:

@Entity data class EntityB( @Id val entityId: String, @AttributeOverrides( AttributeOverride(name = "amount", column = Column(name = "materialCost_amount")), AttributeOverride(name = "currency", column = Column(name = "materialCost_currency")), ) @Embedded val materialCost: CostNullable? = null, ) @Embeddable @Access(AccessType.FIELD) data class CostNullable( val amount: Int?, // use nullable, so that a Java 'Integer' wrapper is used instead of 'int' to avoid Problem 1 val currency: String, ) @Repository interface EntityBRepository : JpaRepository<EntityB, String>

With v6.2.7 we could save and update the entity as follows:

// initial save val fixture = EntityB( entityId = "id1", materialCost = CostNullable(20, "USD") ) val saved = repositoryB.save(fixture) // retrieve var retrieved = repositoryB.findById(fixture.entityId).get() // checks Assertions.assertThat(saved).isEqualTo(fixture) Assertions.assertThat(retrieved).isEqualTo(fixture) // update val fixtureNoCosts = EntityB( entityId = "id1", materialCost = null ) val updated = repositoryB.save(fixtureNoCosts) // check (works with Hibernate 6.2.7, fails with Hibernate 6.2.8) // v6.2.8 returns: EntityB(entityId=id1, materialCost=CostNullable(amount=null, currency=null)) // instead of EntityB(entityId=id1, materialCost=null) Assertions.assertThat(updated).isEqualTo(fixtureNoCosts) // retrieve works as expected retrieved = repositoryB.findById(fixture.entityId).get() Assertions.assertThat(retrieved).isEqualTo(fixtureNoCosts)

With v6.2.8 the repositoryB.save(fixtureNoCosts) returns an entity that has the embedded object set to CostNullable(amount=null, currency=null) which is wrong. When retrieving the same object via findById the embedded object is null as expected.

 

To reproduce use attached demo project:

# run tests with Hibernate 6.2.7 mvn clean install -P 627 # run tests with Hibernate 6.2.8 mvn clean install -P 628

Attachments

1
  • 04 Oct 2023, 04:42 PM

Activity

Show:
Fixed

Details

Assignee

Reporter

Worked in

Sprint

Affects versions

Priority

Created October 4, 2023 at 4:42 PM
Updated October 11, 2023 at 4:57 PM
Resolved October 11, 2023 at 4:51 PM

Flag notifications