From aa9e1f0baf760fa4c659158a6fe238ce37acd35a Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Mon, 16 May 2016 11:14:05 -0500 Subject: [PATCH] HHH-9339 - java.lang.Optional support --- .../org/hibernate/IdentifierLoadAccess.java | 11 ++++ .../org/hibernate/internal/SessionImpl.java | 6 +++ .../main/java/org/hibernate/query/Query.java | 3 ++ .../query/internal/AbstractProducedQuery.java | 6 +++ .../genericApi/BasicGetLoadAccessTest.java | 53 +++++++++++++++++++ 5 files changed, 79 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/IdentifierLoadAccess.java b/hibernate-core/src/main/java/org/hibernate/IdentifierLoadAccess.java index 172d8bca2a..2df475d057 100644 --- a/hibernate-core/src/main/java/org/hibernate/IdentifierLoadAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/IdentifierLoadAccess.java @@ -7,6 +7,7 @@ package org.hibernate; import java.io.Serializable; +import java.util.Optional; /** * Loads an entity by its primary identifier. @@ -57,4 +58,14 @@ public interface IdentifierLoadAccess { * @return The persistent instance or {@code null} */ T load(Serializable id); + + /** + * Same semantic as {@link #load} except that here {@link Optional} is returned to + * handle nullability. + * + * @param id The identifier + * + * @return The persistent instance, if one, wrapped in Optional + */ + Optional loadOptional(Serializable id); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index 70c68b7080..21c509c86c 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -26,6 +26,7 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import javax.persistence.CacheRetrieveMode; import javax.persistence.CacheStoreMode; @@ -2732,6 +2733,11 @@ public final class SessionImpl } } + @Override + public Optional loadOptional(Serializable id) { + return Optional.ofNullable( load( id ) ); + } + @SuppressWarnings("unchecked") protected final T doLoad(Serializable id) { if ( this.lockOptions != null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/Query.java b/hibernate-core/src/main/java/org/hibernate/query/Query.java index 74a99d0e28..f702908f6b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/Query.java +++ b/hibernate-core/src/main/java/org/hibernate/query/Query.java @@ -12,6 +12,7 @@ import java.time.OffsetDateTime; import java.time.ZonedDateTime; import java.util.Calendar; import java.util.Date; +import java.util.Optional; import java.util.stream.Stream; import javax.persistence.FlushModeType; import javax.persistence.LockModeType; @@ -57,6 +58,8 @@ public interface Query extends TypedQuery, org.hibernate.Query, CommonQ */ RowSelection getQueryOptions(); + Optional uniqueResultOptional(); + /** * Retrieve a Stream over the query results. *

diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java b/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java index fe842f6044..9c31756cac 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.Spliterator; import java.util.Spliterators; @@ -1325,6 +1326,11 @@ public abstract class AbstractProducedQuery implements QueryImplementor { return stream; } + @Override + public Optional uniqueResultOptional() { + return Optional.ofNullable( uniqueResult() ); + } + @Override public List list() { beforeQuery(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/genericApi/BasicGetLoadAccessTest.java b/hibernate-core/src/test/java/org/hibernate/test/ops/genericApi/BasicGetLoadAccessTest.java index 321cf62dc6..fd720632f8 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/ops/genericApi/BasicGetLoadAccessTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/ops/genericApi/BasicGetLoadAccessTest.java @@ -6,6 +6,8 @@ */ package org.hibernate.test.ops.genericApi; +import java.util.NoSuchElementException; +import java.util.Optional; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @@ -20,6 +22,11 @@ import org.hibernate.boot.MetadataSources; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; import org.junit.Test; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + /** * @author Steve Ebersole */ @@ -138,4 +145,50 @@ public class BasicGetLoadAccessTest extends BaseNonConfigCoreFunctionalTestCase s.getTransaction().commit(); s.close(); } + + @Test + public void testNullLoadResult() { + Session s = openSession(); + s.beginTransaction(); + + assertNull( s.byId( User.class ).load( -1 ) ); + + Optional user = s.byId( User.class ).loadOptional( -1 ); + assertNotNull( user ); + assertFalse( user.isPresent() ); + try { + user.get(); + fail( "Expecting call to Optional#get to throw NoSuchElementException" ); + } + catch (NoSuchElementException expected) { + // the expected result... + } + + s.getTransaction().commit(); + s.close(); + + } + + @Test + public void testNullQueryResult() { + Session s = openSession(); + s.beginTransaction(); + + assertNull( s.createQuery( "select u from User u where u.id = -1" ).uniqueResult() ); + + Optional user = s.createQuery( "select u from User u where u.id = -1" ).uniqueResultOptional(); + assertNotNull( user ); + assertFalse( user.isPresent() ); + try { + user.get(); + fail( "Expecting call to Optional#get to throw NoSuchElementException" ); + } + catch (NoSuchElementException expected) { + // the expected result... + } + + s.getTransaction().commit(); + s.close(); + + } }