jjbuchan / docs

0 stars 0 forks source link

Hibernate PersistentBag Bug #16

Open jjbuchan opened 3 years ago

jjbuchan commented 3 years ago

https://hibernate.atlassian.net/browse/HHH-5409

This bug appears whenever we try to compare two entities that contain lists. The lists will be treated as PersistentBag and that object type does not implement equals.

For example this assertion will fail

org.assertj.core.api.Assertions.assertThat(Collections.singleton(clonedMonitor))
        .usingElementComparatorIgnoringFields("createdTimestamp", "updatedTimestamp",
            "id", "tenantId", "content", "interval")
        .containsExactly(monitor);

because the monitorMetadataFields, pluginMetadataFields, and zones are all lists that will be lazily loaded (zones is set to FetchType.EAGER - see below to see why it fails).

Due to equals not being implemented, the assert will eventually fall through to hit this conditional and fail - Arrays.isArray(o1) && Arrays.isArray(o2). Both isArray calls will return false.

To avoid this problem you must add the List fields to the ignored fields and then test them directly

Assertions.assertThat(clonedMonitor.getZones()).containsExactlyInAnyOrderElementsOf(
    monitor.getZones());
Assertions.assertThat(clonedMonitor.getMonitorMetadataFields()).containsExactlyInAnyOrderElementsOf(
    monitor.getMonitorMetadataFields());
Assertions.assertThat(clonedMonitor.getPluginMetadataFields()).containsExactlyInAnyOrderElementsOf(
    monitor.getPluginMetadataFields()

FetchType.EAGER Failures

Fields that are annotated with EAGER retrieval will sometimes work within the above assert and othertimes fail. The reason is that when performing a repository.save() for a brand new object it will convert an ArrayList to a PersistentBag but if you are performing the save() on an existing object (i.e. doing an update) it will keep the type as ArrayList.

For this reason, tests involving updates should not need to ignore the zones field but those involved in creating or cloning objects will.