From f86cf085cd38933189a5d126a6bd6db3966da515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Wittner?= Date: Fri, 26 Nov 2021 01:02:33 +0100 Subject: [PATCH 01/11] extend DataAccessUtils --- .../dao/support/DataAccessUtils.java | 111 +++++++++++++++++- .../dao/support/DataAccessUtilsTests.java | 107 ++++++++++++----- 2 files changed, 187 insertions(+), 31 deletions(-) diff --git a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java index adb80a3afb7a..d5413e30bf5c 100644 --- a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java +++ b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java @@ -17,6 +17,11 @@ package org.springframework.dao.support; import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; import org.springframework.dao.DataAccessException; import org.springframework.dao.EmptyResultDataAccessException; @@ -56,6 +61,109 @@ public static T singleResult(@Nullable Collection results) throws Incorre return results.iterator().next(); } + /** + * Return a single result object from the given Stream. + *

Returns {@code null} if 0 result objects found; + * throws an exception if more than 1 element found. + * @param results the result Stream (can be {@code null}) + * @return the single result object, or {@code null} if none + * @throws IncorrectResultSizeDataAccessException if more than one + * element has been found in the given Stream + */ + @Nullable + public static T singleResult(@Nullable Stream results) throws IncorrectResultSizeDataAccessException { + if (results == null) { + return null; + } + List resultList = results.toList(); + if (resultList.size() > 1) { + throw new IncorrectResultSizeDataAccessException(1, resultList.size()); + } + return resultList.stream().findFirst().orElse(null); + } + + /** + * Return a single result object from the given Iterator. + *

Returns {@code null} if 0 result objects found; + * throws an exception if more than 1 element found. + * @param results the result Iterator (can be {@code null}) + * @return the single result object, or {@code null} if none + * @throws IncorrectResultSizeDataAccessException if more than one + * element has been found in the given Iterator + */ + @Nullable + public static T singleResult(@Nullable Iterator results) throws IncorrectResultSizeDataAccessException { + if (results == null) { + return null; + } + Iterable iterable = () -> results; + List resultList = StreamSupport.stream(iterable.spliterator(), false).toList(); + if (resultList.size() > 1) { + throw new IncorrectResultSizeDataAccessException(1, resultList.size()); + } + return resultList.stream().findFirst().orElse(null); + } + + /** + * Return a single result object from the given Collection. + *

Returns {@code Optional.empty()} if 0 result objects found; + * throws an exception if more than 1 element found. + * @param results the result Collection (can be {@code null}) + * @return the single optional result object, or {@code Optional.empty()} if none + * @throws IncorrectResultSizeDataAccessException if more than one + * element has been found in the given Collection + */ + public static Optional optionalResult(@Nullable Collection results) throws IncorrectResultSizeDataAccessException { + if (CollectionUtils.isEmpty(results)) { + return Optional.empty(); + } + if (results.size() > 1) { + throw new IncorrectResultSizeDataAccessException(1, results.size()); + } + return results.stream().findFirst(); + } + + /** + * Return a single result object from the given Stream. + *

Returns {@code Optional.empty()} if 0 result objects found; + * throws an exception if more than 1 element found. + * @param results the result Stream (can be {@code null}) + * @return the single optional result object, or {@code Optional.empty()} if none + * @throws IncorrectResultSizeDataAccessException if more than one + * element has been found in the given Stream + */ + public static Optional optionalResult(@Nullable Stream results) throws IncorrectResultSizeDataAccessException { + if (results == null) { + return Optional.empty(); + } + List resultList = results.toList(); + if (resultList.size() > 1) { + throw new IncorrectResultSizeDataAccessException(1, resultList.size()); + } + return resultList.stream().findFirst(); + } + + /** + * Return a single result object from the given Iterator. + *

Returns {@code Optional.empty()} if 0 result objects found; + * throws an exception if more than 1 element found. + * @param results the result Iterator (can be {@code null}) + * @return the single optional result object, or {@code Optional.empty()} if none + * @throws IncorrectResultSizeDataAccessException if more than one + * element has been found in the given Iterator + */ + public static Optional optionalResult(@Nullable Iterator results) throws IncorrectResultSizeDataAccessException { + if (results == null) { + return Optional.empty(); + } + Iterable iterable = () -> results; + List resultList = StreamSupport.stream(iterable.spliterator(), false).toList(); + if (resultList.size() > 1) { + throw new IncorrectResultSizeDataAccessException(1, resultList.size()); + } + return resultList.stream().findFirst(); + } + /** * Return a single result object from the given Collection. *

Throws an exception if 0 or more than 1 element found. @@ -180,7 +288,7 @@ else if (Number.class.isAssignableFrom(requiredType) && result instanceof Number else { throw new TypeMismatchDataAccessException( "Result object is of type [" + result.getClass().getName() + - "] and could not be converted to required type [" + requiredType.getName() + "]"); + "] and could not be converted to required type [" + requiredType.getName() + "]"); } } return (T) result; @@ -242,5 +350,4 @@ public static RuntimeException translateIfNecessary( DataAccessException dae = pet.translateExceptionIfPossible(rawException); return (dae != null ? dae : rawException); } - } diff --git a/spring-tx/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java b/spring-tx/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java index 8d5ac6e9412f..4f8f129fe4f6 100644 --- a/spring-tx/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java +++ b/spring-tx/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java @@ -16,17 +16,9 @@ package org.springframework.dao.support; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; +import java.util.*; import java.util.function.Consumer; - import org.junit.jupiter.api.Test; - import org.springframework.dao.DataAccessException; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; @@ -47,21 +39,28 @@ public void withEmptyCollection() { assertThat(DataAccessUtils.uniqueResult(col)).isNull(); + assertThat(DataAccessUtils.singleResult(col)).isNull(); + assertThat(DataAccessUtils.singleResult(col.stream())).isNull(); + assertThat(DataAccessUtils.singleResult(col.iterator())).isNull(); + assertThat(DataAccessUtils.optionalResult(col)).isEmpty(); + assertThat(DataAccessUtils.optionalResult(col.stream())).isEmpty(); + assertThat(DataAccessUtils.optionalResult(col.iterator())).isEmpty(); + assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.requiredUniqueResult(col)) - .satisfies(sizeRequirements(1, 0)); + DataAccessUtils.requiredUniqueResult(col)) + .satisfies(sizeRequirements(1, 0)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.objectResult(col, String.class)) - .satisfies(sizeRequirements(1, 0)); + DataAccessUtils.objectResult(col, String.class)) + .satisfies(sizeRequirements(1, 0)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.intResult(col)) - .satisfies(sizeRequirements(1, 0)); + DataAccessUtils.intResult(col)) + .satisfies(sizeRequirements(1, 0)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.longResult(col)) - .satisfies(sizeRequirements(1, 0)); + DataAccessUtils.longResult(col)) + .satisfies(sizeRequirements(1, 0)); } @Test @@ -71,24 +70,48 @@ public void withTooLargeCollection() { col.add("test2"); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.uniqueResult(col)) - .satisfies(sizeRequirements(1, 2)); + DataAccessUtils.uniqueResult(col)) + .satisfies(sizeRequirements(1, 2)); + + assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> + DataAccessUtils.requiredUniqueResult(col)) + .satisfies(sizeRequirements(1, 2)); + + assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> + DataAccessUtils.objectResult(col, String.class)) + .satisfies(sizeRequirements(1, 2)); + + assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> + DataAccessUtils.intResult(col)) + .satisfies(sizeRequirements(1, 2)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.requiredUniqueResult(col)) - .satisfies(sizeRequirements(1, 2)); + DataAccessUtils.longResult(col)) + .satisfies(sizeRequirements(1, 2)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.objectResult(col, String.class)) - .satisfies(sizeRequirements(1, 2)); + DataAccessUtils.singleResult(col)) + .satisfies(sizeRequirements(1, 2)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.intResult(col)) - .satisfies(sizeRequirements(1, 2)); + DataAccessUtils.singleResult(col.stream())) + .satisfies(sizeRequirements(1, 2)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.longResult(col)) - .satisfies(sizeRequirements(1, 2)); + DataAccessUtils.singleResult(col.iterator())) + .satisfies(sizeRequirements(1, 2)); + + assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> + DataAccessUtils.optionalResult(col)) + .satisfies(sizeRequirements(1, 2)); + + assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> + DataAccessUtils.optionalResult(col.stream())) + .satisfies(sizeRequirements(1, 2)); + + assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> + DataAccessUtils.optionalResult(col.iterator())) + .satisfies(sizeRequirements(1, 2)); } @Test @@ -102,6 +125,12 @@ public void withInteger() { assertThat(DataAccessUtils.objectResult(col, String.class)).isEqualTo("5"); assertThat(DataAccessUtils.intResult(col)).isEqualTo(5); assertThat(DataAccessUtils.longResult(col)).isEqualTo(5); + assertThat(DataAccessUtils.singleResult(col)).isEqualTo(5); + assertThat(DataAccessUtils.singleResult(col.stream())).isEqualTo(5); + assertThat(DataAccessUtils.singleResult(col.iterator())).isEqualTo(5); + assertThat(DataAccessUtils.optionalResult(col)).isEqualTo(Optional.of(5)); + assertThat(DataAccessUtils.optionalResult(col.stream())).isEqualTo(Optional.of(5)); + assertThat(DataAccessUtils.optionalResult(col.iterator())).isEqualTo(Optional.of(5)); } @Test @@ -124,8 +153,8 @@ public void withEquivalentIntegerInstanceTwice() { Collection col = Arrays.asList(Integer.valueOf(555), Integer.valueOf(555)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class) - .isThrownBy(() -> DataAccessUtils.uniqueResult(col)) - .satisfies(sizeRequirements(1, 2)); + .isThrownBy(() -> DataAccessUtils.uniqueResult(col)) + .satisfies(sizeRequirements(1, 2)); } @Test @@ -139,6 +168,12 @@ public void withLong() { assertThat(DataAccessUtils.objectResult(col, String.class)).isEqualTo("5"); assertThat(DataAccessUtils.intResult(col)).isEqualTo(5); assertThat(DataAccessUtils.longResult(col)).isEqualTo(5); + assertThat(DataAccessUtils.singleResult(col)).isEqualTo(Long.valueOf(5L)); + assertThat(DataAccessUtils.singleResult(col.stream())).isEqualTo(Long.valueOf(5L)); + assertThat(DataAccessUtils.singleResult(col.iterator())).isEqualTo(Long.valueOf(5L)); + assertThat(DataAccessUtils.optionalResult(col)).isEqualTo(Optional.of(5L)); + assertThat(DataAccessUtils.optionalResult(col.stream())).isEqualTo(Optional.of(5L)); + assertThat(DataAccessUtils.optionalResult(col.iterator())).isEqualTo(Optional.of(5L)); } @Test @@ -149,12 +184,20 @@ public void withString() { assertThat(DataAccessUtils.uniqueResult(col)).isEqualTo("test1"); assertThat(DataAccessUtils.requiredUniqueResult(col)).isEqualTo("test1"); assertThat(DataAccessUtils.objectResult(col, String.class)).isEqualTo("test1"); + assertThat(DataAccessUtils.singleResult(col)).isEqualTo("test1"); + assertThat(DataAccessUtils.singleResult(col.stream())).isEqualTo("test1"); + assertThat(DataAccessUtils.singleResult(col.iterator())).isEqualTo("test1"); + assertThat(DataAccessUtils.optionalResult(col)).isEqualTo(Optional.of("test1")); + assertThat(DataAccessUtils.optionalResult(col.stream())).isEqualTo(Optional.of("test1")); + assertThat(DataAccessUtils.optionalResult(col.iterator())).isEqualTo(Optional.of("test1")); assertThatExceptionOfType(TypeMismatchDataAccessException.class).isThrownBy(() -> DataAccessUtils.intResult(col)); assertThatExceptionOfType(TypeMismatchDataAccessException.class).isThrownBy(() -> DataAccessUtils.longResult(col)); + + } @Test @@ -167,6 +210,12 @@ public void withDate() { assertThat(DataAccessUtils.requiredUniqueResult(col)).isEqualTo(date); assertThat(DataAccessUtils.objectResult(col, Date.class)).isEqualTo(date); assertThat(DataAccessUtils.objectResult(col, String.class)).isEqualTo(date.toString()); + assertThat(DataAccessUtils.singleResult(col)).isEqualTo(date); + assertThat(DataAccessUtils.singleResult(col.stream())).isEqualTo(date); + assertThat(DataAccessUtils.singleResult(col.iterator())).isEqualTo(date); + assertThat(DataAccessUtils.optionalResult(col)).isEqualTo(Optional.of(date)); + assertThat(DataAccessUtils.optionalResult(col.stream())).isEqualTo(Optional.of(date)); + assertThat(DataAccessUtils.optionalResult(col.iterator())).isEqualTo(Optional.of(date)); assertThatExceptionOfType(TypeMismatchDataAccessException.class).isThrownBy(() -> DataAccessUtils.intResult(col)); From ff503c7f74eb26d0ee7383ca53856ec03467d10d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Wittner?= Date: Fri, 26 Nov 2021 01:26:21 +0100 Subject: [PATCH 02/11] cleanup --- .../dao/support/DataAccessUtils.java | 3 +- .../dao/support/DataAccessUtilsTests.java | 68 +++++++++---------- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java index d5413e30bf5c..a5156386b9d3 100644 --- a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java +++ b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java @@ -288,7 +288,7 @@ else if (Number.class.isAssignableFrom(requiredType) && result instanceof Number else { throw new TypeMismatchDataAccessException( "Result object is of type [" + result.getClass().getName() + - "] and could not be converted to required type [" + requiredType.getName() + "]"); + "] and could not be converted to required type [" + requiredType.getName() + "]"); } } return (T) result; @@ -350,4 +350,5 @@ public static RuntimeException translateIfNecessary( DataAccessException dae = pet.translateExceptionIfPossible(rawException); return (dae != null ? dae : rawException); } + } diff --git a/spring-tx/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java b/spring-tx/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java index 4f8f129fe4f6..09a50f9b7a41 100644 --- a/spring-tx/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java +++ b/spring-tx/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java @@ -18,7 +18,9 @@ import java.util.*; import java.util.function.Consumer; + import org.junit.jupiter.api.Test; + import org.springframework.dao.DataAccessException; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; @@ -47,20 +49,20 @@ public void withEmptyCollection() { assertThat(DataAccessUtils.optionalResult(col.iterator())).isEmpty(); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.requiredUniqueResult(col)) - .satisfies(sizeRequirements(1, 0)); + DataAccessUtils.requiredUniqueResult(col)) + .satisfies(sizeRequirements(1, 0)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.objectResult(col, String.class)) - .satisfies(sizeRequirements(1, 0)); + DataAccessUtils.objectResult(col, String.class)) + .satisfies(sizeRequirements(1, 0)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.intResult(col)) - .satisfies(sizeRequirements(1, 0)); + DataAccessUtils.intResult(col)) + .satisfies(sizeRequirements(1, 0)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.longResult(col)) - .satisfies(sizeRequirements(1, 0)); + DataAccessUtils.longResult(col)) + .satisfies(sizeRequirements(1, 0)); } @Test @@ -70,48 +72,48 @@ public void withTooLargeCollection() { col.add("test2"); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.uniqueResult(col)) - .satisfies(sizeRequirements(1, 2)); + DataAccessUtils.uniqueResult(col)) + .satisfies(sizeRequirements(1, 2)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.requiredUniqueResult(col)) - .satisfies(sizeRequirements(1, 2)); + DataAccessUtils.requiredUniqueResult(col)) + .satisfies(sizeRequirements(1, 2)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.objectResult(col, String.class)) - .satisfies(sizeRequirements(1, 2)); + DataAccessUtils.objectResult(col, String.class)) + .satisfies(sizeRequirements(1, 2)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.intResult(col)) - .satisfies(sizeRequirements(1, 2)); + DataAccessUtils.intResult(col)) + .satisfies(sizeRequirements(1, 2)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.longResult(col)) - .satisfies(sizeRequirements(1, 2)); + DataAccessUtils.longResult(col)) + .satisfies(sizeRequirements(1, 2)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.singleResult(col)) - .satisfies(sizeRequirements(1, 2)); + DataAccessUtils.singleResult(col)) + .satisfies(sizeRequirements(1, 2)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.singleResult(col.stream())) - .satisfies(sizeRequirements(1, 2)); + DataAccessUtils.singleResult(col.stream())) + .satisfies(sizeRequirements(1, 2)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.singleResult(col.iterator())) - .satisfies(sizeRequirements(1, 2)); + DataAccessUtils.singleResult(col.iterator())) + .satisfies(sizeRequirements(1, 2)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.optionalResult(col)) - .satisfies(sizeRequirements(1, 2)); + DataAccessUtils.optionalResult(col)) + .satisfies(sizeRequirements(1, 2)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.optionalResult(col.stream())) - .satisfies(sizeRequirements(1, 2)); + DataAccessUtils.optionalResult(col.stream())) + .satisfies(sizeRequirements(1, 2)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> - DataAccessUtils.optionalResult(col.iterator())) - .satisfies(sizeRequirements(1, 2)); + DataAccessUtils.optionalResult(col.iterator())) + .satisfies(sizeRequirements(1, 2)); } @Test @@ -153,8 +155,8 @@ public void withEquivalentIntegerInstanceTwice() { Collection col = Arrays.asList(Integer.valueOf(555), Integer.valueOf(555)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class) - .isThrownBy(() -> DataAccessUtils.uniqueResult(col)) - .satisfies(sizeRequirements(1, 2)); + .isThrownBy(() -> DataAccessUtils.uniqueResult(col)) + .satisfies(sizeRequirements(1, 2)); } @Test @@ -196,8 +198,6 @@ public void withString() { assertThatExceptionOfType(TypeMismatchDataAccessException.class).isThrownBy(() -> DataAccessUtils.longResult(col)); - - } @Test From b98e7ad15d573bfa846d38b41b0661ae39c7f123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Wittner?= Date: Fri, 26 Nov 2021 20:19:55 +0100 Subject: [PATCH 03/11] optimize imports, refactor iterator usage --- .../dao/support/DataAccessUtils.java | 27 +++++++++---------- .../dao/support/DataAccessUtilsTests.java | 9 ++++++- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java index a5156386b9d3..c5933609ce06 100644 --- a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java +++ b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java @@ -21,7 +21,6 @@ import java.util.List; import java.util.Optional; import java.util.stream.Stream; -import java.util.stream.StreamSupport; import org.springframework.dao.DataAccessException; import org.springframework.dao.EmptyResultDataAccessException; @@ -75,11 +74,11 @@ public static T singleResult(@Nullable Stream results) throws IncorrectRe if (results == null) { return null; } - List resultList = results.toList(); + List resultList = results.limit(2).toList(); if (resultList.size() > 1) { throw new IncorrectResultSizeDataAccessException(1, resultList.size()); } - return resultList.stream().findFirst().orElse(null); + return CollectionUtils.isEmpty(resultList) ? null : resultList.get(0); } /** @@ -96,12 +95,11 @@ public static T singleResult(@Nullable Iterator results) throws Incorrect if (results == null) { return null; } - Iterable iterable = () -> results; - List resultList = StreamSupport.stream(iterable.spliterator(), false).toList(); - if (resultList.size() > 1) { - throw new IncorrectResultSizeDataAccessException(1, resultList.size()); + T result = results.hasNext() ? results.next() : null; + if (results.hasNext()) { + throw new IncorrectResultSizeDataAccessException(1, 2); } - return resultList.stream().findFirst().orElse(null); + return result; } /** @@ -136,11 +134,11 @@ public static Optional optionalResult(@Nullable Stream results) throws if (results == null) { return Optional.empty(); } - List resultList = results.toList(); + List resultList = results.limit(2).toList(); if (resultList.size() > 1) { throw new IncorrectResultSizeDataAccessException(1, resultList.size()); } - return resultList.stream().findFirst(); + return CollectionUtils.isEmpty(resultList) ? Optional.empty() : Optional.of(resultList.get(0)); } /** @@ -156,12 +154,11 @@ public static Optional optionalResult(@Nullable Iterator results) thro if (results == null) { return Optional.empty(); } - Iterable iterable = () -> results; - List resultList = StreamSupport.stream(iterable.spliterator(), false).toList(); - if (resultList.size() > 1) { - throw new IncorrectResultSizeDataAccessException(1, resultList.size()); + T result = results.hasNext() ? results.next() : null; + if (results.hasNext()) { + throw new IncorrectResultSizeDataAccessException(1, 2); } - return resultList.stream().findFirst(); + return Optional.ofNullable(result); } /** diff --git a/spring-tx/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java b/spring-tx/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java index 09a50f9b7a41..92218d0a7410 100644 --- a/spring-tx/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java +++ b/spring-tx/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java @@ -16,7 +16,14 @@ package org.springframework.dao.support; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; import java.util.function.Consumer; import org.junit.jupiter.api.Test; From 8a5fc7d42bfef5a4c51e1adfe2392e10065f0c43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Wittner?= Date: Sat, 27 Nov 2021 14:48:41 +0100 Subject: [PATCH 04/11] close streams properly with try-with-resource --- .../dao/support/DataAccessUtils.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java index c5933609ce06..0d4fe8531dad 100644 --- a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java +++ b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java @@ -74,11 +74,13 @@ public static T singleResult(@Nullable Stream results) throws IncorrectRe if (results == null) { return null; } - List resultList = results.limit(2).toList(); - if (resultList.size() > 1) { - throw new IncorrectResultSizeDataAccessException(1, resultList.size()); + try (results) { + List resultList = results.limit(2).toList(); + if (resultList.size() > 1) { + throw new IncorrectResultSizeDataAccessException(1, resultList.size()); + } + return CollectionUtils.isEmpty(resultList) ? null : resultList.get(0); } - return CollectionUtils.isEmpty(resultList) ? null : resultList.get(0); } /** @@ -134,11 +136,13 @@ public static Optional optionalResult(@Nullable Stream results) throws if (results == null) { return Optional.empty(); } - List resultList = results.limit(2).toList(); - if (resultList.size() > 1) { - throw new IncorrectResultSizeDataAccessException(1, resultList.size()); + try (results) { + List resultList = results.limit(2).toList(); + if (resultList.size() > 1) { + throw new IncorrectResultSizeDataAccessException(1, resultList.size()); + } + return CollectionUtils.isEmpty(resultList) ? Optional.empty() : Optional.of(resultList.get(0)); } - return CollectionUtils.isEmpty(resultList) ? Optional.empty() : Optional.of(resultList.get(0)); } /** From 1e7d103ef28d2d71953b538b1af3d695b0333f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Wittner?= <95002361+KaidosGH@users.noreply.github.com> Date: Sun, 28 Nov 2021 04:02:07 +0100 Subject: [PATCH 05/11] Update spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java re-use newly added singleResult methods Co-authored-by: Vigneswaran --- .../org/springframework/dao/support/DataAccessUtils.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java index 0d4fe8531dad..fd789518af54 100644 --- a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java +++ b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java @@ -114,13 +114,7 @@ public static T singleResult(@Nullable Iterator results) throws Incorrect * element has been found in the given Collection */ public static Optional optionalResult(@Nullable Collection results) throws IncorrectResultSizeDataAccessException { - if (CollectionUtils.isEmpty(results)) { - return Optional.empty(); - } - if (results.size() > 1) { - throw new IncorrectResultSizeDataAccessException(1, results.size()); - } - return results.stream().findFirst(); + return Optional.ofNullable(singleResult(results)); } /** From 6522003c31a7217a57f7072157c005633c09829b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Wittner?= <95002361+KaidosGH@users.noreply.github.com> Date: Sun, 28 Nov 2021 04:02:16 +0100 Subject: [PATCH 06/11] Update spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java re-use newly added singleResult methods Co-authored-by: Vigneswaran --- .../springframework/dao/support/DataAccessUtils.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java index fd789518af54..85a092ce0102 100644 --- a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java +++ b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java @@ -127,15 +127,7 @@ public static Optional optionalResult(@Nullable Collection results) th * element has been found in the given Stream */ public static Optional optionalResult(@Nullable Stream results) throws IncorrectResultSizeDataAccessException { - if (results == null) { - return Optional.empty(); - } - try (results) { - List resultList = results.limit(2).toList(); - if (resultList.size() > 1) { - throw new IncorrectResultSizeDataAccessException(1, resultList.size()); - } - return CollectionUtils.isEmpty(resultList) ? Optional.empty() : Optional.of(resultList.get(0)); + return Optional.ofNullable(singleResult(results)); } } From 4ee08be619d964efaac39345699aa97fdeadf5f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Wittner?= <95002361+KaidosGH@users.noreply.github.com> Date: Sun, 28 Nov 2021 04:02:24 +0100 Subject: [PATCH 07/11] Update spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java re-use newly added singleResult methods Co-authored-by: Vigneswaran --- .../org/springframework/dao/support/DataAccessUtils.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java index 85a092ce0102..17dd72ab6dd3 100644 --- a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java +++ b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java @@ -141,14 +141,7 @@ public static Optional optionalResult(@Nullable Stream results) throws * element has been found in the given Iterator */ public static Optional optionalResult(@Nullable Iterator results) throws IncorrectResultSizeDataAccessException { - if (results == null) { - return Optional.empty(); - } - T result = results.hasNext() ? results.next() : null; - if (results.hasNext()) { - throw new IncorrectResultSizeDataAccessException(1, 2); - } - return Optional.ofNullable(result); + return Optional.ofNullable(singleResult(results)); } /** From 3017bebc5bf1dfc7e779706c87ff1fb6b767eb7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Wittner?= Date: Sun, 28 Nov 2021 04:03:17 +0100 Subject: [PATCH 08/11] fix closing bracket --- .../java/org/springframework/dao/support/DataAccessUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java index 17dd72ab6dd3..95db075cdc9a 100644 --- a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java +++ b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java @@ -128,7 +128,6 @@ public static Optional optionalResult(@Nullable Collection results) th */ public static Optional optionalResult(@Nullable Stream results) throws IncorrectResultSizeDataAccessException { return Optional.ofNullable(singleResult(results)); - } } /** From 9206303d453566cd040d1014aad8cbdc78e56387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Wittner?= <95002361+KaidosGH@users.noreply.github.com> Date: Sun, 28 Nov 2021 15:10:48 +0100 Subject: [PATCH 09/11] Update spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java use "public IncorrectResultSizeDataAccessException(int expectedSize)" in stream and iterator method Co-authored-by: Kwangyong Kim --- .../java/org/springframework/dao/support/DataAccessUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java index 95db075cdc9a..453d74693093 100644 --- a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java +++ b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java @@ -77,7 +77,7 @@ public static T singleResult(@Nullable Stream results) throws IncorrectRe try (results) { List resultList = results.limit(2).toList(); if (resultList.size() > 1) { - throw new IncorrectResultSizeDataAccessException(1, resultList.size()); + throw new IncorrectResultSizeDataAccessException(1); } return CollectionUtils.isEmpty(resultList) ? null : resultList.get(0); } From 7c096e0683570f8fd99da129de25a80be5bf3e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Wittner?= <95002361+KaidosGH@users.noreply.github.com> Date: Sun, 28 Nov 2021 15:10:56 +0100 Subject: [PATCH 10/11] Update spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java use "public IncorrectResultSizeDataAccessException(int expectedSize)" in stream and iterator method Co-authored-by: Vigneswaran --- .../java/org/springframework/dao/support/DataAccessUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java index 453d74693093..ce359d4be574 100644 --- a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java +++ b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java @@ -99,7 +99,7 @@ public static T singleResult(@Nullable Iterator results) throws Incorrect } T result = results.hasNext() ? results.next() : null; if (results.hasNext()) { - throw new IncorrectResultSizeDataAccessException(1, 2); + throw new IncorrectResultSizeDataAccessException(1); } return result; } From 1891fa45b5d43a3741905531f8b84944a7c820e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Wittner?= Date: Sun, 28 Nov 2021 15:25:33 +0100 Subject: [PATCH 11/11] update tests to correctly assert the thrown exception --- .../dao/support/DataAccessUtilsTests.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/spring-tx/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java b/spring-tx/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java index 92218d0a7410..0efee06ca6ac 100644 --- a/spring-tx/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java +++ b/spring-tx/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java @@ -104,11 +104,11 @@ public void withTooLargeCollection() { assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> DataAccessUtils.singleResult(col.stream())) - .satisfies(sizeRequirements(1, 2)); + .satisfies(sizeRequirements(1)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> DataAccessUtils.singleResult(col.iterator())) - .satisfies(sizeRequirements(1, 2)); + .satisfies(sizeRequirements(1)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> DataAccessUtils.optionalResult(col)) @@ -116,11 +116,11 @@ public void withTooLargeCollection() { assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> DataAccessUtils.optionalResult(col.stream())) - .satisfies(sizeRequirements(1, 2)); + .satisfies(sizeRequirements(1)); assertThatExceptionOfType(IncorrectResultSizeDataAccessException.class).isThrownBy(() -> DataAccessUtils.optionalResult(col.iterator())) - .satisfies(sizeRequirements(1, 2)); + .satisfies(sizeRequirements(1)); } @Test @@ -255,6 +255,13 @@ private Consumer sizeRequi }; } + private Consumer sizeRequirements( + int expectedSize) { + return ex -> { + assertThat(ex.getExpectedSize()).as("expected size").isEqualTo(expectedSize); + }; + } + public static class MapPersistenceExceptionTranslator implements PersistenceExceptionTranslator { // in to out