From 7ddcb6c67aaa8b7bbbaef5a9891e753a6c8aad21 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Sat, 4 Jan 2025 10:20:34 +0100 Subject: [PATCH 1/4] [#2007] NPE retrieving Entity with composite id mixing ManyToOne with basic attributes --- .../ReactiveNonAggregatedIdentifierMappingInitializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveNonAggregatedIdentifierMappingInitializer.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveNonAggregatedIdentifierMappingInitializer.java index 0096e8d0f..5228e397e 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveNonAggregatedIdentifierMappingInitializer.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveNonAggregatedIdentifierMappingInitializer.java @@ -62,7 +62,7 @@ public CompletionStage reactiveResolveKey(NonAggregatedIdentifierMappingIn final RowProcessingState rowProcessingState = data.getRowProcessingState(); final boolean[] dataIsMissing = {false}; return loop( getInitializers(), initializer -> { - if ( dataIsMissing[0] ) { + if ( dataIsMissing[0] || initializer == null ) { return voidFuture(); } final InitializerData subData = ( (ReactiveInitializer) initializer ) From 031a20391857689bd9c2432151b6cf32390ed6fa Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Sat, 4 Jan 2025 10:20:16 +0100 Subject: [PATCH 2/4] [#2007] Add test for NPE retrieving Entity with composite id mixing ManyToOne with basic attributes --- .../reactive/ManyToOneIdClassTest.java | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 hibernate-reactive-core/src/test/java/org/hibernate/reactive/ManyToOneIdClassTest.java diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ManyToOneIdClassTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ManyToOneIdClassTest.java new file mode 100644 index 000000000..a1d1d882e --- /dev/null +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ManyToOneIdClassTest.java @@ -0,0 +1,141 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive; + +import java.util.Collection; +import java.util.List; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.vertx.junit5.Timeout; +import io.vertx.junit5.VertxTestContext; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.ManyToOne; + +import static java.util.concurrent.TimeUnit.MINUTES; +import static org.assertj.core.api.Assertions.assertThat; + +@Timeout(value = 1, timeUnit = MINUTES) +public class ManyToOneIdClassTest extends BaseReactiveTest { + + private final static String USER_NAME = "user"; + private final static String SUBSYSTEM_ID = "1"; + + @Override + protected Collection> annotatedEntities() { + return List.of( SystemUser.class, Subsystem.class ); + } + + @BeforeEach + public void populateDb(VertxTestContext context) { + Subsystem subsystem = new Subsystem( SUBSYSTEM_ID, "sub 1" ); + SystemUser systemUser = new SystemUser( subsystem, USER_NAME, "system 1" ); + test( + context, getMutinySessionFactory() + .withTransaction( (s, t) -> s.persistAll( subsystem, systemUser ) ) + ); + } + + @AfterEach + public void after(VertxTestContext context) { + test( context, cleanDb() ); + } + + @Test + public void testQuery(VertxTestContext context) { + test( + context, openSession() + .thenAccept( session -> session.createQuery( "SELECT s FROM SystemUser s", SystemUser.class ) + .getResultList().thenAccept( list -> { + assertThat( list.size() ).isEqualTo( 1 ); + SystemUser systemUser = list.get( 0 ); + assertThat( systemUser.getSubsystem().getId() ).isEqualTo( SUBSYSTEM_ID ); + assertThat( systemUser.getUsername() ).isEqualTo( USER_NAME ); + } ) ) + ); + } + + @Entity(name = "SystemUser") + @IdClass(PK.class) + public static class SystemUser { + + @Id + @ManyToOne(fetch = FetchType.LAZY) + private Subsystem subsystem; + + @Id + private String username; + + private String name; + + public SystemUser() { + } + + public SystemUser(Subsystem subsystem, String username, String name) { + this.subsystem = subsystem; + this.username = username; + this.name = name; + } + + public Subsystem getSubsystem() { + return subsystem; + } + + public String getUsername() { + return username; + } + + public String getName() { + return name; + } + } + + @Entity(name = "Subsystem") + public static class Subsystem { + + @Id + private String id; + + private String description; + + public Subsystem() { + } + + public Subsystem(String id, String description) { + this.id = id; + this.description = description; + } + + public String getId() { + return id; + } + + public String getDescription() { + return description; + } + } + + public static class PK { + + private Subsystem subsystem; + + private String username; + + public PK(Subsystem subsystem, String username) { + this.subsystem = subsystem; + this.username = username; + } + + private PK() { + } + } + +} From df0b5ad80544e9973b277b1c3783bb0e3a3900ef Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 7 Jan 2025 14:19:40 +0100 Subject: [PATCH 3/4] [#2007] Remove obsolete code --- .../ReactiveNonAggregatedIdentifierMappingInitializer.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveNonAggregatedIdentifierMappingInitializer.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveNonAggregatedIdentifierMappingInitializer.java index 5228e397e..51f7d59b7 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveNonAggregatedIdentifierMappingInitializer.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveNonAggregatedIdentifierMappingInitializer.java @@ -60,9 +60,8 @@ public CompletionStage reactiveResolveKey(NonAggregatedIdentifierMappingIn } else { final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final boolean[] dataIsMissing = {false}; return loop( getInitializers(), initializer -> { - if ( dataIsMissing[0] || initializer == null ) { + if ( initializer == null ) { return voidFuture(); } final InitializerData subData = ( (ReactiveInitializer) initializer ) @@ -72,7 +71,6 @@ public CompletionStage reactiveResolveKey(NonAggregatedIdentifierMappingIn .thenAccept( v -> { if ( subData.getState() == State.MISSING ) { data.setState( State.MISSING ); - dataIsMissing[0] = true; } } ); } ); From 1056448b1ab659403b38cb932171f068f9177366 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 7 Jan 2025 14:17:53 +0100 Subject: [PATCH 4/4] [#2007] Minor test clean up --- .../reactive/ManyToOneIdClassTest.java | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ManyToOneIdClassTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ManyToOneIdClassTest.java index a1d1d882e..73dead49a 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ManyToOneIdClassTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ManyToOneIdClassTest.java @@ -8,7 +8,6 @@ import java.util.Collection; import java.util.List; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -40,26 +39,21 @@ public void populateDb(VertxTestContext context) { SystemUser systemUser = new SystemUser( subsystem, USER_NAME, "system 1" ); test( context, getMutinySessionFactory() - .withTransaction( (s, t) -> s.persistAll( subsystem, systemUser ) ) + .withTransaction( s -> s.persistAll( subsystem, systemUser ) ) ); } - @AfterEach - public void after(VertxTestContext context) { - test( context, cleanDb() ); - } - @Test public void testQuery(VertxTestContext context) { test( - context, openSession() - .thenAccept( session -> session.createQuery( "SELECT s FROM SystemUser s", SystemUser.class ) - .getResultList().thenAccept( list -> { - assertThat( list.size() ).isEqualTo( 1 ); - SystemUser systemUser = list.get( 0 ); - assertThat( systemUser.getSubsystem().getId() ).isEqualTo( SUBSYSTEM_ID ); - assertThat( systemUser.getUsername() ).isEqualTo( USER_NAME ); - } ) ) + context, openSession().thenAccept( session -> session + .createQuery( "FROM SystemUser s", SystemUser.class ) + .getResultList().thenAccept( list -> { + assertThat( list ).hasSize( 1 ); + SystemUser systemUser = list.get( 0 ); + assertThat( systemUser.getSubsystem().getId() ).isEqualTo( SUBSYSTEM_ID ); + assertThat( systemUser.getUsername() ).isEqualTo( USER_NAME ); + } ) ) ); }