Re-enabled stream tests
This commit is contained in:
parent
acd78256eb
commit
36fa3fca8e
|
@ -132,6 +132,10 @@ public interface Query<R> extends TypedQuery<R>, CommonQueryContract {
|
||||||
return list();
|
return list();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default Stream<R> getResultStream() {
|
||||||
|
return stream();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method to return a single instance that matches
|
* Convenience method to return a single instance that matches
|
||||||
* the query, or {@code null} if the query returns no results.
|
* the query, or {@code null} if the query returns no results.
|
||||||
|
|
|
@ -0,0 +1,196 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.stream.basic;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import jakarta.persistence.Tuple;
|
||||||
|
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||||
|
import jakarta.persistence.criteria.CriteriaQuery;
|
||||||
|
import jakarta.persistence.criteria.Root;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.core.Is.is;
|
||||||
|
import static org.hamcrest.core.IsEqual.equalTo;
|
||||||
|
import static org.hibernate.testing.orm.junit.ExtraAssertions.assertTyping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@DomainModel(
|
||||||
|
annotatedClasses = BasicStreamTest.MyEntity.class
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
public class BasicStreamTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void basicStreamTest(SessionFactoryScope scope) {
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
// mainly we want to make sure that closing the Stream releases the ScrollableResults too
|
||||||
|
assertThat( ( (SessionImplementor) session ).getJdbcCoordinator()
|
||||||
|
.getLogicalConnection()
|
||||||
|
.getResourceRegistry()
|
||||||
|
.hasRegisteredResources(), is( false ) );
|
||||||
|
final Stream<MyEntity> stream = session.createQuery( "from MyEntity", MyEntity.class ).stream();
|
||||||
|
try {
|
||||||
|
stream.forEach( System.out::println );
|
||||||
|
assertThat( session.getJdbcCoordinator()
|
||||||
|
.getLogicalConnection()
|
||||||
|
.getResourceRegistry()
|
||||||
|
.hasRegisteredResources(), is( true ) );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
stream.close();
|
||||||
|
assertThat( session.getJdbcCoordinator()
|
||||||
|
.getLogicalConnection()
|
||||||
|
.getResourceRegistry()
|
||||||
|
.hasRegisteredResources(), is( false ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-10824")
|
||||||
|
public void testQueryStream(SessionFactoryScope scope) {
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
MyEntity e = new MyEntity();
|
||||||
|
e.id = 1;
|
||||||
|
e.name = "Test";
|
||||||
|
session.persist( e );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.inSession(
|
||||||
|
session -> {
|
||||||
|
// Test stream query without type.
|
||||||
|
try (Stream stream = session.createQuery( "From MyEntity" ).stream()) {
|
||||||
|
Object result = stream.findFirst().orElse( null );
|
||||||
|
assertTyping( MyEntity.class, result );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test stream query with type.
|
||||||
|
try (final Stream<MyEntity> stream = session.createQuery( "From MyEntity", MyEntity.class )
|
||||||
|
.stream()) {
|
||||||
|
assertTyping( MyEntity.class, stream.findFirst().orElse( null ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test stream query using forEach
|
||||||
|
try (Stream<MyEntity> stream = session.createQuery( "From MyEntity", MyEntity.class )
|
||||||
|
.stream()) {
|
||||||
|
stream.forEach( i -> {
|
||||||
|
assertTyping( MyEntity.class, i );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
try (Stream<Object[]> stream = session.createQuery( "SELECT me.id, me.name FROM MyEntity me" )
|
||||||
|
.stream()) {
|
||||||
|
stream.forEach( i -> {
|
||||||
|
assertTyping( Integer.class, i[0] );
|
||||||
|
assertTyping( String.class, i[1] );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-11743")
|
||||||
|
public void testTupleStream(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
MyEntity entity = new MyEntity();
|
||||||
|
entity.id = 2;
|
||||||
|
entity.name = "an entity";
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
//test tuple stream using criteria
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
CriteriaBuilder cb = session.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Tuple> criteria = cb.createTupleQuery();
|
||||||
|
Root<MyEntity> me = criteria.from( MyEntity.class );
|
||||||
|
criteria.multiselect( me.get( "id" ), me.get( "name" ) );
|
||||||
|
try (Stream<Tuple> data = session.createQuery( criteria ).stream()) {
|
||||||
|
data.forEach( tuple -> assertTyping( Tuple.class, tuple ) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
//test tuple stream using JPQL
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
try (Stream<Tuple> data = session.createQuery( "SELECT me.id, me.name FROM MyEntity me", Tuple.class )
|
||||||
|
.stream()) {
|
||||||
|
data.forEach( tuple -> assertTyping( Tuple.class, tuple ) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void basicStreamTestWithExplicitOnClose(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
AtomicInteger onCloseCount = new AtomicInteger();
|
||||||
|
|
||||||
|
// mainly we want to make sure that closing the Stream releases the ScrollableResults too
|
||||||
|
assertThat( session.getJdbcCoordinator()
|
||||||
|
.getLogicalConnection()
|
||||||
|
.getResourceRegistry()
|
||||||
|
.hasRegisteredResources(), is( false ) );
|
||||||
|
|
||||||
|
assertThat( onCloseCount.get(), equalTo( 0 ) );
|
||||||
|
|
||||||
|
try (final Stream<MyEntity> stream = session.createQuery( "from MyEntity", MyEntity.class )
|
||||||
|
.stream()
|
||||||
|
.onClose(
|
||||||
|
onCloseCount::incrementAndGet )) {
|
||||||
|
|
||||||
|
|
||||||
|
assertThat( onCloseCount.get(), equalTo( 0 ) );
|
||||||
|
|
||||||
|
stream.forEach( System.out::println );
|
||||||
|
assertThat( session.getJdbcCoordinator()
|
||||||
|
.getLogicalConnection()
|
||||||
|
.getResourceRegistry()
|
||||||
|
.hasRegisteredResources(), is( true ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat( session.getJdbcCoordinator()
|
||||||
|
.getLogicalConnection()
|
||||||
|
.getResourceRegistry()
|
||||||
|
.hasRegisteredResources(), is( false ) );
|
||||||
|
|
||||||
|
assertThat( onCloseCount.get(), equalTo( 1 ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "MyEntity")
|
||||||
|
@Table(name = "MyEntity")
|
||||||
|
public static class MyEntity {
|
||||||
|
@Id
|
||||||
|
public Integer id;
|
||||||
|
public String name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.stream.basic;
|
package org.hibernate.orm.test.stream.basic;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
@ -17,9 +17,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import jakarta.persistence.Entity;
|
|
||||||
import jakarta.persistence.Id;
|
|
||||||
import jakarta.persistence.Table;
|
|
||||||
|
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.dialect.H2Dialect;
|
import org.hibernate.dialect.H2Dialect;
|
||||||
|
@ -28,46 +25,53 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.internal.util.ReflectHelper;
|
import org.hibernate.internal.util.ReflectHelper;
|
||||||
import org.hibernate.resource.jdbc.ResourceRegistry;
|
import org.hibernate.resource.jdbc.ResourceRegistry;
|
||||||
|
|
||||||
import org.hibernate.testing.RequiresDialect;
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.junit.Test;
|
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
import static org.hibernate.testing.orm.junit.ExtraAssertions.assertTyping;
|
||||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class JpaStreamTest extends BaseNonConfigCoreFunctionalTestCase {
|
@DomainModel(
|
||||||
|
annotatedClasses = JpaStreamTest.MyEntity.class
|
||||||
@Override
|
)
|
||||||
protected Class[] getAnnotatedClasses() {
|
@SessionFactory
|
||||||
return new Class[] { MyEntity.class };
|
public class JpaStreamTest {
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-11907")
|
@TestForIssue(jiraKey = "HHH-11907")
|
||||||
public void testQueryStream() {
|
public void testQueryStream(SessionFactoryScope scope) {
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
MyEntity e= new MyEntity();
|
MyEntity e = new MyEntity();
|
||||||
e.id = 1;
|
e.id = 1;
|
||||||
e.name = "Test";
|
e.name = "Test";
|
||||||
session.persist( e );
|
session.persist( e );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
// Test stream query without type.
|
// Test stream query without type.
|
||||||
Object result = session.createQuery( "From MyEntity" ).getResultStream().findFirst().orElse( null );
|
Object result = session.createQuery( "From MyEntity" ).getResultStream().findFirst().orElse( null );
|
||||||
assertTyping( MyEntity.class, result );
|
assertTyping( MyEntity.class, result );
|
||||||
|
|
||||||
// Test stream query with type.
|
// Test stream query with type.
|
||||||
result = session.createQuery( "From MyEntity", MyEntity.class ).getResultStream().findFirst().orElse( null );
|
result = session.createQuery( "From MyEntity", MyEntity.class )
|
||||||
|
.getResultStream()
|
||||||
|
.findFirst()
|
||||||
|
.orElse( null );
|
||||||
assertTyping( MyEntity.class, result );
|
assertTyping( MyEntity.class, result );
|
||||||
|
|
||||||
// Test stream query using forEach
|
// Test stream query using forEach
|
||||||
|
@ -79,15 +83,15 @@ public class JpaStreamTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
data.forEach( i -> {
|
data.forEach( i -> {
|
||||||
assertTyping( Integer.class, i[0] );
|
assertTyping( Integer.class, i[0] );
|
||||||
assertTyping( String.class, i[1] );
|
assertTyping( String.class, i[1] );
|
||||||
});
|
} );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@RequiresDialect(H2Dialect.class)
|
@RequiresDialect(H2Dialect.class)
|
||||||
@TestForIssue( jiraKey = {"HHH-13872", "HHH-14449"})
|
@TestForIssue(jiraKey = { "HHH-13872", "HHH-14449" })
|
||||||
public void testStreamCloseOnTerminalOperation() {
|
public void testStreamCloseOnTerminalOperation(SessionFactoryScope scope) {
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
session.createQuery( "delete from MyEntity" ).executeUpdate();
|
session.createQuery( "delete from MyEntity" ).executeUpdate();
|
||||||
|
|
||||||
for ( int i = 1; i <= 10; i++ ) {
|
for ( int i = 1; i <= 10; i++ ) {
|
||||||
|
@ -104,7 +108,7 @@ public class JpaStreamTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
|
||||||
// run without onClose callbacks
|
// run without onClose callbacks
|
||||||
|
|
||||||
this.runTerminalOperationTests(noOp, Collections.emptyList(), noOp, false, false);
|
this.runTerminalOperationTests( noOp, Collections.emptyList(), noOp, false, false, scope );
|
||||||
|
|
||||||
AtomicInteger onClose1Count = new AtomicInteger();
|
AtomicInteger onClose1Count = new AtomicInteger();
|
||||||
AtomicInteger onClose2Count = new AtomicInteger();
|
AtomicInteger onClose2Count = new AtomicInteger();
|
||||||
|
@ -131,7 +135,8 @@ public class JpaStreamTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
assertThat( onClose3Count ).hasValue( 1 );
|
assertThat( onClose3Count ).hasValue( 1 );
|
||||||
},
|
},
|
||||||
false, // no flatMap before onClose
|
false, // no flatMap before onClose
|
||||||
false // no flatMap after onClose
|
false, // no flatMap after onClose
|
||||||
|
scope
|
||||||
);
|
);
|
||||||
|
|
||||||
this.runTerminalOperationTests(
|
this.runTerminalOperationTests(
|
||||||
|
@ -153,7 +158,8 @@ public class JpaStreamTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
assertThat( onClose3Count ).hasValue( 1 );
|
assertThat( onClose3Count ).hasValue( 1 );
|
||||||
},
|
},
|
||||||
true, // run a flatMap operation before onClose
|
true, // run a flatMap operation before onClose
|
||||||
false // no flatMap after onClose
|
false, // no flatMap after onClose
|
||||||
|
scope
|
||||||
);
|
);
|
||||||
|
|
||||||
this.runTerminalOperationTests(
|
this.runTerminalOperationTests(
|
||||||
|
@ -175,7 +181,8 @@ public class JpaStreamTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
assertThat( onClose3Count ).hasValue( 1 );
|
assertThat( onClose3Count ).hasValue( 1 );
|
||||||
},
|
},
|
||||||
false, // no flatMap before onClose
|
false, // no flatMap before onClose
|
||||||
true // run a flatMap operation after onClose
|
true, // run a flatMap operation after onClose
|
||||||
|
scope
|
||||||
);
|
);
|
||||||
|
|
||||||
this.runTerminalOperationTests(
|
this.runTerminalOperationTests(
|
||||||
|
@ -197,192 +204,290 @@ public class JpaStreamTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
assertThat( onClose3Count ).hasValue( 1 );
|
assertThat( onClose3Count ).hasValue( 1 );
|
||||||
},
|
},
|
||||||
true, // run a flatMap operation before onClose
|
true, // run a flatMap operation before onClose
|
||||||
true // run a flatMap operation after onClose
|
true, // run a flatMap operation after onClose
|
||||||
|
scope
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runTerminalOperationTests(
|
private void runTerminalOperationTests(
|
||||||
Runnable prepare, List<Runnable> onCloseCallbacks, Runnable onCloseAssertion,
|
Runnable prepare, List<Runnable> onCloseCallbacks,
|
||||||
boolean flatMapBefore, boolean flatMapAfter) {
|
Runnable onCloseAssertion,
|
||||||
|
boolean flatMapBefore,
|
||||||
|
boolean flatMapAfter,
|
||||||
|
SessionFactoryScope scope) {
|
||||||
|
|
||||||
// collect as list
|
// collect as list
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
Stream<MyEntity> stream = getMyEntityStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter);
|
Stream<MyEntity> stream = getMyEntityStream(
|
||||||
|
prepare,
|
||||||
ResourceRegistry resourceRegistry = resourceRegistry(session);
|
session,
|
||||||
assertTrue( resourceRegistry.hasRegisteredResources() );
|
onCloseCallbacks,
|
||||||
|
flatMapBefore,
|
||||||
List<MyEntity> entities = stream.collect( Collectors.toList() ) ;
|
flatMapAfter
|
||||||
assertEquals(10, entities.size());
|
);
|
||||||
|
ResourceRegistry resourceRegistry = resourceRegistry( session );
|
||||||
assertFalse( resourceRegistry.hasRegisteredResources() );
|
try {
|
||||||
|
List<MyEntity> entities = stream.collect( Collectors.toList() );
|
||||||
|
assertTrue( resourceRegistry.hasRegisteredResources() );
|
||||||
|
assertEquals( 10, entities.size() );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
stream.close();
|
||||||
|
assertFalse( resourceRegistry.hasRegisteredResources() );
|
||||||
|
}
|
||||||
onCloseAssertion.run();
|
onCloseAssertion.run();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// forEach (TestCase based on attachment EntityManagerIllustrationTest.java in HHH-14449)
|
// forEach (TestCase based on attachment EntityManagerIllustrationTest.java in HHH-14449)
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
Stream<MyEntity> stream = getMyEntityStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter);
|
Stream<MyEntity> stream = getMyEntityStream(
|
||||||
|
prepare,
|
||||||
|
session,
|
||||||
|
onCloseCallbacks,
|
||||||
|
flatMapBefore,
|
||||||
|
flatMapAfter
|
||||||
|
);
|
||||||
|
|
||||||
ResourceRegistry resourceRegistry = resourceRegistry(session);
|
ResourceRegistry resourceRegistry = resourceRegistry( session );
|
||||||
assertTrue( resourceRegistry.hasRegisteredResources() );
|
try {
|
||||||
|
AtomicInteger count = new AtomicInteger();
|
||||||
|
|
||||||
AtomicInteger count = new AtomicInteger();
|
stream.forEach( myEntity -> count.incrementAndGet() );
|
||||||
|
assertTrue( resourceRegistry.hasRegisteredResources() );
|
||||||
|
|
||||||
stream.forEach(myEntity -> count.incrementAndGet());
|
assertEquals( 10, count.get() );
|
||||||
|
}
|
||||||
assertEquals(10, count.get());
|
finally {
|
||||||
|
stream.close();
|
||||||
assertFalse( resourceRegistry.hasRegisteredResources() );
|
assertFalse( resourceRegistry.hasRegisteredResources() );
|
||||||
|
}
|
||||||
|
|
||||||
onCloseAssertion.run();
|
onCloseAssertion.run();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// filter (always true) + forEach (TestCase based on attachment EntityManagerIllustrationTest.java in HHH-14449)
|
// filter (always true) + forEach (TestCase based on attachment EntityManagerIllustrationTest.java in HHH-14449)
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
Stream<MyEntity> stream = getMyEntityStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter);
|
Stream<MyEntity> stream = getMyEntityStream(
|
||||||
|
prepare,
|
||||||
|
session,
|
||||||
|
onCloseCallbacks,
|
||||||
|
flatMapBefore,
|
||||||
|
flatMapAfter
|
||||||
|
);
|
||||||
|
|
||||||
ResourceRegistry resourceRegistry = resourceRegistry(session);
|
ResourceRegistry resourceRegistry = resourceRegistry( session );
|
||||||
assertTrue( resourceRegistry.hasRegisteredResources() );
|
|
||||||
|
|
||||||
AtomicInteger count = new AtomicInteger();
|
try {
|
||||||
|
AtomicInteger count = new AtomicInteger();
|
||||||
|
|
||||||
stream.filter(Objects::nonNull).forEach(myEntity -> count.incrementAndGet());
|
stream.filter( Objects::nonNull ).forEach( myEntity -> count.incrementAndGet() );
|
||||||
|
assertTrue( resourceRegistry.hasRegisteredResources() );
|
||||||
assertEquals(10, count.get());
|
assertEquals( 10, count.get() );
|
||||||
|
}
|
||||||
assertFalse( resourceRegistry.hasRegisteredResources() );
|
finally {
|
||||||
|
stream.close();
|
||||||
|
assertFalse( resourceRegistry.hasRegisteredResources() );
|
||||||
|
}
|
||||||
|
|
||||||
onCloseAssertion.run();
|
onCloseAssertion.run();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// filter (partially true) + forEach (TestCase based on attachment EntityManagerIllustrationTest.java in HHH-14449)
|
// filter (partially true) + forEach (TestCase based on attachment EntityManagerIllustrationTest.java in HHH-14449)
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
Stream<MyEntity> stream = getMyEntityStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter);
|
Stream<MyEntity> stream = getMyEntityStream(
|
||||||
|
prepare,
|
||||||
|
session,
|
||||||
|
onCloseCallbacks,
|
||||||
|
flatMapBefore,
|
||||||
|
flatMapAfter
|
||||||
|
);
|
||||||
|
|
||||||
ResourceRegistry resourceRegistry = resourceRegistry(session);
|
ResourceRegistry resourceRegistry = resourceRegistry( session );
|
||||||
assertTrue( resourceRegistry.hasRegisteredResources() );
|
|
||||||
|
|
||||||
AtomicInteger count = new AtomicInteger();
|
try {
|
||||||
|
AtomicInteger count = new AtomicInteger();
|
||||||
|
|
||||||
stream.filter(entity -> entity.getId() % 2 == 0).forEach(myEntity -> count.incrementAndGet());
|
stream.filter( entity -> entity.getId() % 2 == 0 ).forEach( myEntity -> count.incrementAndGet() );
|
||||||
|
assertTrue( resourceRegistry.hasRegisteredResources() );
|
||||||
assertEquals(5, count.get());
|
assertEquals( 5, count.get() );
|
||||||
|
}
|
||||||
assertFalse( resourceRegistry.hasRegisteredResources() );
|
finally {
|
||||||
|
stream.close();
|
||||||
|
assertFalse( resourceRegistry.hasRegisteredResources() );
|
||||||
|
}
|
||||||
|
|
||||||
onCloseAssertion.run();
|
onCloseAssertion.run();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// multiple chained operations (TestCase based on attachment EntityManagerIllustrationTest.java in HHH-14449)
|
// multiple chained operations (TestCase based on attachment EntityManagerIllustrationTest.java in HHH-14449)
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
Stream<MyEntity> stream = getMyEntityStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter);
|
Stream<MyEntity> stream = getMyEntityStream(
|
||||||
|
prepare,
|
||||||
|
session,
|
||||||
|
onCloseCallbacks,
|
||||||
|
flatMapBefore,
|
||||||
|
flatMapAfter
|
||||||
|
);
|
||||||
|
|
||||||
ResourceRegistry resourceRegistry = resourceRegistry(session);
|
ResourceRegistry resourceRegistry = resourceRegistry( session );
|
||||||
assertTrue( resourceRegistry.hasRegisteredResources() );
|
|
||||||
|
|
||||||
AtomicInteger count = new AtomicInteger();
|
try {
|
||||||
|
AtomicInteger count = new AtomicInteger();
|
||||||
|
|
||||||
stream
|
stream
|
||||||
.filter(Objects::nonNull)
|
.filter( Objects::nonNull )
|
||||||
.map(Optional::of)
|
.map( Optional::of )
|
||||||
.filter(Optional::isPresent)
|
.filter( Optional::isPresent )
|
||||||
.map(Optional::get)
|
.map( Optional::get )
|
||||||
.forEach(myEntity -> count.incrementAndGet());
|
.forEach( myEntity -> count.incrementAndGet() );
|
||||||
|
assertTrue( resourceRegistry.hasRegisteredResources() );
|
||||||
|
|
||||||
assertEquals(10, count.get());
|
assertEquals( 10, count.get() );
|
||||||
|
}
|
||||||
assertFalse( resourceRegistry.hasRegisteredResources() );
|
finally {
|
||||||
|
stream.close();
|
||||||
|
assertFalse( resourceRegistry.hasRegisteredResources() );
|
||||||
|
}
|
||||||
|
|
||||||
onCloseAssertion.run();
|
onCloseAssertion.run();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// mapToInt
|
// mapToInt
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
Stream<MyEntity> stream = getMyEntityStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter);
|
Stream<MyEntity> stream = getMyEntityStream(
|
||||||
|
prepare,
|
||||||
|
session,
|
||||||
|
onCloseCallbacks,
|
||||||
|
flatMapBefore,
|
||||||
|
flatMapAfter
|
||||||
|
);
|
||||||
|
|
||||||
ResourceRegistry resourceRegistry = resourceRegistry(session);
|
ResourceRegistry resourceRegistry = resourceRegistry( session );
|
||||||
assertTrue( resourceRegistry.hasRegisteredResources() );
|
try {
|
||||||
|
int sum = stream.mapToInt( MyEntity::getId ).sum();
|
||||||
|
assertTrue( resourceRegistry.hasRegisteredResources() );
|
||||||
|
|
||||||
int sum = stream.mapToInt( MyEntity::getId ).sum();
|
assertEquals( 55, sum );
|
||||||
assertEquals(55, sum);
|
}
|
||||||
|
finally {
|
||||||
assertFalse( resourceRegistry.hasRegisteredResources() );
|
stream.close();
|
||||||
|
assertFalse( resourceRegistry.hasRegisteredResources() );
|
||||||
|
}
|
||||||
|
|
||||||
onCloseAssertion.run();
|
onCloseAssertion.run();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// mapToLong
|
// mapToLong
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
Stream<MyEntity> stream = getMyEntityStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter);
|
Stream<MyEntity> stream = getMyEntityStream(
|
||||||
|
prepare,
|
||||||
|
session,
|
||||||
|
onCloseCallbacks,
|
||||||
|
flatMapBefore,
|
||||||
|
flatMapAfter
|
||||||
|
);
|
||||||
|
|
||||||
ResourceRegistry resourceRegistry = resourceRegistry(session);
|
ResourceRegistry resourceRegistry = resourceRegistry( session );
|
||||||
assertTrue( resourceRegistry.hasRegisteredResources() );
|
|
||||||
|
|
||||||
long result = stream.mapToLong( entity -> entity.id * 10 ).min().getAsLong();
|
try {
|
||||||
assertEquals(10, result);
|
long result = stream.mapToLong( entity -> entity.id * 10 ).min().getAsLong();
|
||||||
|
assertTrue( resourceRegistry.hasRegisteredResources() );
|
||||||
assertFalse( resourceRegistry.hasRegisteredResources() );
|
assertEquals( 10, result );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
stream.close();
|
||||||
|
assertFalse( resourceRegistry.hasRegisteredResources() );
|
||||||
|
}
|
||||||
|
|
||||||
onCloseAssertion.run();
|
onCloseAssertion.run();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// mapToDouble
|
// mapToDouble
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
Stream<MyEntity> stream = getMyEntityStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter);
|
Stream<MyEntity> stream = getMyEntityStream(
|
||||||
|
prepare,
|
||||||
|
session,
|
||||||
|
onCloseCallbacks,
|
||||||
|
flatMapBefore,
|
||||||
|
flatMapAfter
|
||||||
|
);
|
||||||
|
|
||||||
ResourceRegistry resourceRegistry = resourceRegistry(session);
|
ResourceRegistry resourceRegistry = resourceRegistry( session );
|
||||||
assertTrue( resourceRegistry.hasRegisteredResources() );
|
try {
|
||||||
|
double result = stream.mapToDouble( entity -> entity.id * 0.1D ).max().getAsDouble();
|
||||||
|
assertTrue( resourceRegistry.hasRegisteredResources() );
|
||||||
|
|
||||||
double result = stream.mapToDouble( entity -> entity.id * 0.1D ).max().getAsDouble();
|
assertEquals( 1, result, 0.1 );
|
||||||
assertEquals(1, result, 0.1);
|
}
|
||||||
|
finally {
|
||||||
assertFalse( resourceRegistry.hasRegisteredResources() );
|
stream.close();
|
||||||
|
assertFalse( resourceRegistry.hasRegisteredResources() );
|
||||||
|
}
|
||||||
|
|
||||||
onCloseAssertion.run();
|
onCloseAssertion.run();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
//Test call close explicitly
|
//Test call close explicitly
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
|
try (Stream<Long> stream = getLongStream(
|
||||||
try (Stream<Long> stream = getLongStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter)) {
|
prepare,
|
||||||
|
session,
|
||||||
|
onCloseCallbacks,
|
||||||
|
flatMapBefore,
|
||||||
|
flatMapAfter
|
||||||
|
)) {
|
||||||
|
|
||||||
ResourceRegistry resourceRegistry = resourceRegistry( session );
|
ResourceRegistry resourceRegistry = resourceRegistry( session );
|
||||||
assertTrue( resourceRegistry.hasRegisteredResources() );
|
try {
|
||||||
|
Object[] result = stream.sorted().skip( 5 ).limit( 5 ).toArray();
|
||||||
|
assertTrue( resourceRegistry.hasRegisteredResources() );
|
||||||
|
|
||||||
Object[] result = stream.sorted().skip( 5 ).limit( 5 ).toArray();
|
assertEquals( 5, result.length );
|
||||||
assertEquals( 5, result.length );
|
assertEquals( 6, result[0] );
|
||||||
assertEquals( 6, result[0] );
|
assertEquals( 10, result[4] );
|
||||||
assertEquals( 10, result[4] );
|
|
||||||
|
|
||||||
assertFalse( resourceRegistry.hasRegisteredResources() );
|
}
|
||||||
|
finally {
|
||||||
|
stream.close();
|
||||||
|
assertFalse( resourceRegistry.hasRegisteredResources() );
|
||||||
|
}
|
||||||
|
|
||||||
onCloseAssertion.run();
|
onCloseAssertion.run();
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
//Test Java 9 Stream methods
|
//Test Java 9 Stream methods
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
Method takeWhileMethod = ReflectHelper.getMethod( Stream.class, "takeWhile", Predicate.class );
|
Method takeWhileMethod = ReflectHelper.getMethod( Stream.class, "takeWhile", Predicate.class );
|
||||||
|
|
||||||
if ( takeWhileMethod != null ) {
|
if ( takeWhileMethod != null ) {
|
||||||
try (Stream<Long> stream = getLongStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter)) {
|
try (Stream<Long> stream = getLongStream(
|
||||||
|
prepare,
|
||||||
|
session,
|
||||||
|
onCloseCallbacks,
|
||||||
|
flatMapBefore,
|
||||||
|
flatMapAfter
|
||||||
|
)) {
|
||||||
|
|
||||||
ResourceRegistry resourceRegistry = resourceRegistry( session );
|
ResourceRegistry resourceRegistry = resourceRegistry( session );
|
||||||
assertTrue( resourceRegistry.hasRegisteredResources() );
|
try {
|
||||||
|
|
||||||
Predicate<Integer> predicate = id -> id <= 5;
|
Predicate<Integer> predicate = id -> id <= 5;
|
||||||
|
|
||||||
Stream<Integer> takeWhileStream = (Stream<Integer>) takeWhileMethod.invoke( stream, predicate );
|
Stream<Integer> takeWhileStream = (Stream<Integer>) takeWhileMethod.invoke( stream, predicate );
|
||||||
|
|
||||||
List<Integer> result = takeWhileStream.collect( Collectors.toList() );
|
List<Integer> result = takeWhileStream.collect( Collectors.toList() );
|
||||||
|
assertTrue( resourceRegistry.hasRegisteredResources() );
|
||||||
|
|
||||||
assertEquals( 5, result.size() );
|
assertEquals( 5, result.size() );
|
||||||
assertTrue( result.contains( 1 ) );
|
assertTrue( result.contains( 1 ) );
|
||||||
assertTrue( result.contains( 3 ) );
|
assertTrue( result.contains( 3 ) );
|
||||||
assertTrue( result.contains( 5 ) );
|
assertTrue( result.contains( 5 ) );
|
||||||
|
}
|
||||||
assertFalse( resourceRegistry.hasRegisteredResources() );
|
finally {
|
||||||
|
stream.close();
|
||||||
|
assertFalse( resourceRegistry.hasRegisteredResources() );
|
||||||
|
}
|
||||||
|
|
||||||
onCloseAssertion.run();
|
onCloseAssertion.run();
|
||||||
}
|
}
|
||||||
|
@ -392,27 +497,36 @@ public class JpaStreamTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
Method dropWhileMethod = ReflectHelper.getMethod( Stream.class, "dropWhile", Predicate.class );
|
Method dropWhileMethod = ReflectHelper.getMethod( Stream.class, "dropWhile", Predicate.class );
|
||||||
|
|
||||||
if ( dropWhileMethod != null ) {
|
if ( dropWhileMethod != null ) {
|
||||||
try (Stream<Long> stream = getLongStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter)) {
|
try (Stream<Long> stream = getLongStream(
|
||||||
|
prepare,
|
||||||
|
session,
|
||||||
|
onCloseCallbacks,
|
||||||
|
flatMapBefore,
|
||||||
|
flatMapAfter
|
||||||
|
)) {
|
||||||
|
|
||||||
ResourceRegistry resourceRegistry = resourceRegistry( session );
|
ResourceRegistry resourceRegistry = resourceRegistry( session );
|
||||||
assertTrue( resourceRegistry.hasRegisteredResources() );
|
|
||||||
|
|
||||||
Predicate<Integer> predicate = id -> id <= 5;
|
Predicate<Integer> predicate = id -> id <= 5;
|
||||||
|
|
||||||
Stream<Integer> dropWhileStream = (Stream<Integer>) dropWhileMethod.invoke( stream, predicate );
|
Stream<Integer> dropWhileStream = (Stream<Integer>) dropWhileMethod.invoke( stream, predicate );
|
||||||
|
try {
|
||||||
|
List<Integer> result = dropWhileStream.collect( Collectors.toList() );
|
||||||
|
assertTrue( resourceRegistry.hasRegisteredResources() );
|
||||||
|
|
||||||
List<Integer> result = dropWhileStream.collect( Collectors.toList() );
|
assertEquals( 5, result.size() );
|
||||||
|
assertTrue( result.contains( 6 ) );
|
||||||
assertEquals( 5, result.size() );
|
assertTrue( result.contains( 8 ) );
|
||||||
assertTrue( result.contains( 6 ) );
|
assertTrue( result.contains( 10 ) );
|
||||||
assertTrue( result.contains( 8 ) );
|
}
|
||||||
assertTrue( result.contains( 10 ) );
|
finally {
|
||||||
|
stream.close();
|
||||||
assertFalse( resourceRegistry.hasRegisteredResources() );
|
assertFalse( resourceRegistry.hasRegisteredResources() );
|
||||||
|
}
|
||||||
|
|
||||||
onCloseAssertion.run();
|
onCloseAssertion.run();
|
||||||
}
|
}
|
||||||
|
@ -486,7 +600,7 @@ public class JpaStreamTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity(name = "MyEntity")
|
@Entity(name = "MyEntity")
|
||||||
@Table(name="MyEntity")
|
@Table(name = "MyEntity")
|
||||||
public static class MyEntity {
|
public static class MyEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
|
@ -1,183 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
|
||||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
|
||||||
*/
|
|
||||||
package org.hibernate.test.stream.basic;
|
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
import jakarta.persistence.Entity;
|
|
||||||
import jakarta.persistence.Id;
|
|
||||||
import jakarta.persistence.Table;
|
|
||||||
import jakarta.persistence.Tuple;
|
|
||||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
|
||||||
import jakarta.persistence.criteria.CriteriaQuery;
|
|
||||||
import jakarta.persistence.criteria.Root;
|
|
||||||
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.boot.MetadataSources;
|
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
|
||||||
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
|
||||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
import static org.hamcrest.core.Is.is;
|
|
||||||
import static org.hamcrest.core.IsEqual.equalTo;
|
|
||||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
|
||||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
public class BasicStreamTest extends BaseNonConfigCoreFunctionalTestCase {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void applyMetadataSources(MetadataSources sources) {
|
|
||||||
super.applyMetadataSources( sources );
|
|
||||||
sources.addAnnotatedClass( MyEntity.class );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void basicStreamTest() {
|
|
||||||
Session session = openSession();
|
|
||||||
session.getTransaction().begin();
|
|
||||||
|
|
||||||
// mainly we want to make sure that closing the Stream releases the ScrollableResults too
|
|
||||||
assertThat( ( (SessionImplementor) session ).getJdbcCoordinator().getLogicalConnection().getResourceRegistry().hasRegisteredResources(), is( false ) );
|
|
||||||
final Stream<MyEntity> stream = session.createQuery( "from MyEntity", MyEntity.class ).stream();
|
|
||||||
assertThat( ( (SessionImplementor) session ).getJdbcCoordinator().getLogicalConnection().getResourceRegistry().hasRegisteredResources(), is( true ) );
|
|
||||||
stream.forEach( System.out::println );
|
|
||||||
assertThat( ( (SessionImplementor) session ).getJdbcCoordinator().getLogicalConnection().getResourceRegistry().hasRegisteredResources(), is( false ) );
|
|
||||||
stream.close();
|
|
||||||
assertThat( ( (SessionImplementor) session ).getJdbcCoordinator().getLogicalConnection().getResourceRegistry().hasRegisteredResources(), is( false ) );
|
|
||||||
|
|
||||||
session.getTransaction().commit();
|
|
||||||
session.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@TestForIssue(jiraKey = "HHH-10824")
|
|
||||||
public void testQueryStream() {
|
|
||||||
Session session = openSession();
|
|
||||||
try {
|
|
||||||
|
|
||||||
session.getTransaction().begin();
|
|
||||||
MyEntity e= new MyEntity();
|
|
||||||
e.id = 1;
|
|
||||||
e.name = "Test";
|
|
||||||
session.persist( e );
|
|
||||||
session.getTransaction().commit();
|
|
||||||
session.clear();
|
|
||||||
|
|
||||||
// Test stream query without type.
|
|
||||||
Object result = session.createQuery( "From MyEntity" ).stream().findFirst().orElse( null );
|
|
||||||
assertTyping( MyEntity.class, result );
|
|
||||||
|
|
||||||
// Test stream query with type.
|
|
||||||
result = session.createQuery( "From MyEntity", MyEntity.class ).stream().findFirst().orElse( null );
|
|
||||||
assertTyping( MyEntity.class, result );
|
|
||||||
|
|
||||||
// Test stream query using forEach
|
|
||||||
session.createQuery( "From MyEntity", MyEntity.class ).stream().forEach( i -> {
|
|
||||||
assertTyping( MyEntity.class, i );
|
|
||||||
} );
|
|
||||||
|
|
||||||
Stream<Object[]> data = session.createQuery( "SELECT me.id, me.name FROM MyEntity me" ).stream();
|
|
||||||
data.forEach( i -> {
|
|
||||||
assertTyping( Integer.class, i[0] );
|
|
||||||
assertTyping( String.class, i[1] );
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
session.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@TestForIssue(jiraKey = "HHH-11743")
|
|
||||||
public void testTupleStream() {
|
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
|
||||||
MyEntity entity = new MyEntity();
|
|
||||||
entity.id = 2;
|
|
||||||
entity.name = "an entity";
|
|
||||||
session.persist( entity );
|
|
||||||
} );
|
|
||||||
|
|
||||||
//test tuple stream using criteria
|
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
|
||||||
CriteriaBuilder cb = session.getCriteriaBuilder();
|
|
||||||
CriteriaQuery<Tuple> criteria = cb.createTupleQuery();
|
|
||||||
Root<MyEntity> me = criteria.from( MyEntity.class );
|
|
||||||
criteria.multiselect( me.get( "id" ), me.get( "name" ) );
|
|
||||||
Stream<Tuple> data = session.createQuery( criteria ).stream();
|
|
||||||
data.forEach( tuple -> assertTyping( Tuple.class, tuple ) );
|
|
||||||
} );
|
|
||||||
|
|
||||||
//test tuple stream using JPQL
|
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
|
||||||
Stream<Tuple> data = session.createQuery( "SELECT me.id, me.name FROM MyEntity me", Tuple.class ).stream();
|
|
||||||
data.forEach( tuple -> assertTyping( Tuple.class, tuple ) );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void basicStreamTestWithExplicitOnClose() {
|
|
||||||
Session session = openSession();
|
|
||||||
session.getTransaction().begin();
|
|
||||||
|
|
||||||
AtomicInteger onCloseCount = new AtomicInteger();
|
|
||||||
|
|
||||||
// mainly we want to make sure that closing the Stream releases the ScrollableResults too
|
|
||||||
assertThat( ( (SessionImplementor) session ).getJdbcCoordinator()
|
|
||||||
.getLogicalConnection()
|
|
||||||
.getResourceRegistry()
|
|
||||||
.hasRegisteredResources(), is( false ) );
|
|
||||||
|
|
||||||
assertThat( onCloseCount.get(), equalTo( 0 ) );
|
|
||||||
|
|
||||||
final Stream<MyEntity> stream = session.createQuery( "from MyEntity", MyEntity.class ).stream().onClose(
|
|
||||||
onCloseCount::incrementAndGet );
|
|
||||||
|
|
||||||
assertThat( ( (SessionImplementor) session ).getJdbcCoordinator()
|
|
||||||
.getLogicalConnection()
|
|
||||||
.getResourceRegistry()
|
|
||||||
.hasRegisteredResources(), is( true ) );
|
|
||||||
|
|
||||||
assertThat( onCloseCount.get(), equalTo( 0 ) );
|
|
||||||
|
|
||||||
stream.forEach( System.out::println );
|
|
||||||
|
|
||||||
assertThat( ( (SessionImplementor) session ).getJdbcCoordinator()
|
|
||||||
.getLogicalConnection()
|
|
||||||
.getResourceRegistry()
|
|
||||||
.hasRegisteredResources(), is( false ) );
|
|
||||||
|
|
||||||
assertThat( onCloseCount.get(), equalTo( 1 ) );
|
|
||||||
|
|
||||||
stream.close();
|
|
||||||
|
|
||||||
assertThat( ( (SessionImplementor) session ).getJdbcCoordinator()
|
|
||||||
.getLogicalConnection()
|
|
||||||
.getResourceRegistry()
|
|
||||||
.hasRegisteredResources(), is( false ) );
|
|
||||||
|
|
||||||
assertThat( onCloseCount.get(), equalTo( 1 ) );
|
|
||||||
|
|
||||||
session.getTransaction().commit();
|
|
||||||
session.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity(name = "MyEntity")
|
|
||||||
@Table(name="MyEntity")
|
|
||||||
public static class MyEntity {
|
|
||||||
@Id
|
|
||||||
public Integer id;
|
|
||||||
public String name;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -62,9 +62,9 @@ Passing null or not is now triggered by whether setting the parameter was called
|
||||||
|
|
||||||
=== HQL results
|
=== HQL results
|
||||||
|
|
||||||
Hql queries that joins an Entity `Person` with an Entity `Address` without specifying a select clause `from Address a join a.address` does not return anymore a `List<Object[]>`but a list of `Person`.
|
HQL queries that use joins without specifying a select clause e.g. `from Person p join p.address` do not return a `List<Object[]>` with an entry per join anymore, but a list of `Person`.
|
||||||
|
|
||||||
The hql query `select a,ad from Address a join a.address ad` returns instead a `List<Object[]>`.
|
The HQL query `select p,a from Person p join p.address a` returns instead a `List<Object[]>`.
|
||||||
|
|
||||||
e.g.
|
e.g.
|
||||||
```
|
```
|
||||||
|
@ -85,14 +85,19 @@ class Address {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<A> result = session.createQuery("from Address a join a.address").list()
|
List<Person> result = session.createQuery("from Person p join p.address").list();
|
||||||
|
|
||||||
|
List<Object[]> results = session.createQuery("select p, a from Person p join p.address a").list();
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
==== Stream
|
||||||
|
|
||||||
|
`jakarta.persistence.Query#getResultStream()` and `org.hibernate.query.Query#stream()` do not return a `Stream` decorator anymore, so in order to close the underlying IO resources is now necessary to explicitly call the `Stream#close()` method. The JDK `Stream` documentation is quite explicit about the need for an explicit call to `close` by the user to avoid resource leakages, so we build upon this requirement.
|
||||||
|
|
||||||
==== Iterate
|
==== Iterate
|
||||||
|
|
||||||
The `Query#iterate()` method has been removed.
|
The `Query#iterate()` method has been removed. The alternative is to use `Query#stream()` or `Query#getResultStream()`.
|
||||||
|
|
||||||
=== Native Query
|
=== Native Query
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue