Hibernate 6 NPEs on lazy loaded entities in collection

After upgrading to Hibernate 6 we get NullPointerExceptions when querying the database:

2023-05-19T13:28:21.355+02:00 ERROR 1260 --- [nio-8080-exec-2] ApiController      : ModuleController - An error occurred: Cannot invoke "java.lang.Comparable.compareTo(Object)" because "one" is null

java.lang.NullPointerException: Cannot invoke "java.lang.Comparable.compareTo(Object)" because "one" is null
	at org.hibernate.internal.util.compare.ComparableComparator.compare(ComparableComparator.java:28) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.internal.util.compare.ComparableComparator.compare(ComparableComparator.java:18) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.metamodel.mapping.AttributeMapping.compare(AttributeMapping.java:88) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.metamodel.mapping.EmbeddableMappingType.compare(EmbeddableMappingType.java:264) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.metamodel.mapping.internal.EmbeddedForeignKeyDescriptor.compare(EmbeddedForeignKeyDescriptor.java:212) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.action.internal.CollectionAction.compareTo(CollectionAction.java:156) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.action.internal.CollectionAction.compareTo(CollectionAction.java:30) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at java.base/java.util.ComparableTimSort.binarySort(ComparableTimSort.java:262) ~[na:na]
	at java.base/java.util.ComparableTimSort.sort(ComparableTimSort.java:189) ~[na:na]
	at java.base/java.util.Arrays.sort(Arrays.java:1107) ~[na:na]
	at java.base/java.util.Arrays.sort(Arrays.java:1301) ~[na:na]
	at java.base/java.util.ArrayList.sort(ArrayList.java:1721) ~[na:na]
	at java.base/java.util.Collections.sort(Collections.java:145) ~[na:na]
	at org.hibernate.engine.spi.ExecutableList.sort(ExecutableList.java:253) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.engine.spi.ActionQueue.sortCollectionActions(ActionQueue.java:778) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.event.internal.AbstractFlushingEventListener.flushCollections(AbstractFlushingEventListener.java:325) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:91) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:48) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1375) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.lambda$new$0(ConcreteSqmSelectQueryPlan.java:107) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:302) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:243) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:518) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:367) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.query.spi.AbstractSelectionQuery.getSingleResult(AbstractSelectionQuery.java:473) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at SystemDao.getByUuid(SystemDao.java:23) ~[classes/:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) ~[spring-aop-6.0.9.jar:6.0.9]
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698) ~[spring-aop-6.0.9.jar:6.0.9]
	at SystemDao$$SpringCGLIB$$0.getByUuid(<generated>) ~[classes/:na]

The Dao function looks like this:

var q = em.createQuery(
                "SELECT system FROM System system WHERE system.uuid = :uuid", System.class);
        q.setParameter("uuid", uuid);
        return q.getSingleResult();

And the entity content:

    @Id
    @Column(name = "id", nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "uuid")
    private UUID uuid;

    @Column(name = "group_id")
    private String groupId;

    @Column(name = "name")
    private String name;

    @Column(name = "title")
    private String title;

    @Column(name = "version")
    private String version;

    @ElementCollection
    @CollectionTable(name = "ohh_system_languages", joinColumns = @JoinColumn(name = "system_uuid", referencedColumnName =
            "uuid"))
    @Column(name = "language")
    private Set<Locale> languages = new HashSet<>();

    @OneToMany(mappedBy = "system", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Concept> concepts = new HashSet<>();

    @ManyToMany(mappedBy = "systems")
    private List<Module> module = List.of();

It seems to fail on getting the uuids from the list of modules, they are lazy loaded, but the get doesn’t seem to actually retrieve the data. It just compares 2 null values.

It worked fine with hibernate 5. Is this a bug, or have we misconfigured something?

This looks like a bug. Please create an issue in the issue tracker(https://hibernate.atlassian.net) with a test case(hibernate-test-case-templates/JPAUnitTestCase.java at main · hibernate/hibernate-test-case-templates · GitHub) that reproduces the issue.

It seems I ran into a similar problem, could you please provide the link to the issue in the tracker, so I might get some additional hints?

Unfortunately I haven’t been able to create a simple reproduction scenario using the test case. The test succeeds every time…
If you have a simple scenario that can be reproduced using the test case that would be very helpful.

Thanks for responding @ebakker! Fortunately for me, I found a workaround for my scenario. We had an attribute definition like this:

@ElementCollection
@CollectionTable(
    name = "myTable",
    schema = "mySchema",
    joinColumns = @JoinColumn(name = "remote_id")
)
...
private List<Interval> intervals = new ArrayList<>();

intervals only contained null values, which lead to an NPE during processing. We solved this by extending the collection annotation:

@ElementCollection(fetch = FetchType.EAGER)

Unfortunately for you, this only occurs with our production data, which, of course, I am not allowed to disclose :frowning:
Anyway, I hope you get something useful out of my case :wink: