diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoCodeBlocks.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoCodeBlocks.java index a676ac212f..ddbac63d34 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoCodeBlocks.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoCodeBlocks.java @@ -15,6 +15,7 @@ */ package org.springframework.data.mongodb.repository.aot; +import java.util.Set; import java.util.regex.Pattern; import org.bson.Document; @@ -48,6 +49,7 @@ * {@link CodeBlock} generator for common tasks. * * @author Christoph Strobl + * @author maryantocinn * @since 5.0 */ class MongoCodeBlocks { @@ -237,8 +239,8 @@ static void appendReadPreference(AotQueryMethodGenerationContext context, Builde } /** - * Wraps the given {@link CodeBlock} representing an {@link Iterable} into a {@link Streamable} if the - * {@link MethodReturn} indicates so. + * Adapts the given {@link CodeBlock} representing an {@link Iterable} to the declared collection return type if + * necessary. */ public static CodeBlock potentiallyWrapStreamable(MethodReturn methodReturn, CodeBlock returningIterable) { @@ -255,6 +257,11 @@ public static CodeBlock potentiallyWrapStreamable(MethodReturn methodReturn, Cod returnType, DefaultConversionService.class, Streamable.class, returningIterable, TypeDescriptor.class); } + if (ClassUtils.isAssignable(Set.class, returnType)) { + return CodeBlock.of("$2T.getSharedInstance().convert($3L, $1T.class)", returnType, + DefaultConversionService.class, returningIterable); + } + return returningIterable; } diff --git a/spring-data-mongodb/src/test/java/example/aot/UserRepository.java b/spring-data-mongodb/src/test/java/example/aot/UserRepository.java index 209ae4a798..ce50754bf8 100644 --- a/spring-data-mongodb/src/test/java/example/aot/UserRepository.java +++ b/spring-data-mongodb/src/test/java/example/aot/UserRepository.java @@ -52,6 +52,7 @@ /** * @author Christoph Strobl + * @author maryantocinn */ public interface UserRepository extends CrudRepository { @@ -59,6 +60,8 @@ public interface UserRepository extends CrudRepository { List findUserNoArgumentsBy(); + Set findUserSetBy(); + Streamable streamUserNoArgumentsBy(); User findOneByUsername(String username); @@ -234,6 +237,8 @@ public interface UserRepository extends CrudRepository { List findUserProjectionByLastnameStartingWith(String lastname); + Set findUserProjectionSetByLastnameStartingWith(String lastname); + Page findUserProjectionByLastnameStartingWith(String lastname, Pageable page); Page findUserProjectionByLastnameStartingWith(String lastname, Pageable page, Class projectionType); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/MongoRepositoryContributorTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/MongoRepositoryContributorTests.java index aef7caed04..87d127eff3 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/MongoRepositoryContributorTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/MongoRepositoryContributorTests.java @@ -26,6 +26,7 @@ import java.time.Instant; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.regex.Pattern; import org.bson.BsonString; @@ -79,6 +80,7 @@ * * @author Christoph Strobl * @author Mark Paluch + * @author maryantocinn */ @Testcontainers(disabledWithoutDocker = true) @SpringJUnitConfig(classes = MongoRepositoryContributorTests.MongoRepositoryContributorConfiguration.class) @@ -200,6 +202,15 @@ void testDerivedFinderWithoutArguments() { assertThat(users).hasSize(7).hasOnlyElementsOfType(User.class); } + @Test // GH-5225 + void testDerivedQueryAsSet() { + + Set users = fragment.findUserSetBy(); + + assertThat(users).isInstanceOf(Set.class).extracting(User::getUsername).containsExactlyInAnyOrder("luke", "leia", + "han", "chewbacca", "yoda", "vader", "kylo"); + } + @Test void testCountWorksAsExpected() { @@ -563,6 +574,14 @@ void testDerivedFinderReturningListOfProjections() { assertThat(users).extracting(UserProjection::getUsername).containsExactlyInAnyOrder("han", "kylo", "luke", "vader"); } + @Test // GH-5225 + void testDerivedQueryReturningSetOfProjections() { + + Set users = fragment.findUserProjectionSetByLastnameStartingWith("S"); + assertThat(users).isInstanceOf(Set.class).extracting(UserProjection::getUsername) + .containsExactlyInAnyOrder("han", "kylo", "luke", "vader"); + } + @Test void testDerivedFinderReturningPageOfProjections() { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/QueryMethodContributionUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/QueryMethodContributionUnitTests.java index a96d64cd98..6af1e22965 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/QueryMethodContributionUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/QueryMethodContributionUnitTests.java @@ -64,6 +64,7 @@ * @author Christoph Strobl * @author Mark Paluch * @author Tomasz Forys + * @author maryantocinn */ class QueryMethodContributionUnitTests { @@ -399,6 +400,17 @@ void rendersStreamableReturnType() throws NoSuchMethodException { .containsSubsequence("return", "Streamable.of(", "all())"); } + @Test // GH-5225 + void rendersSetReturnType() throws NoSuchMethodException { + + MethodSpec methodSpec = codeOf(UserRepository.class, "findUserSetBy"); + + assertThat(methodSpec.toString()) // + .contains("DefaultConversionService.getSharedInstance().convert(") // + .containsSubsequence("return", "all()", "Set.class") // + .doesNotContain("return finder.matching(filterQuery).all()"); + } + @Test // GH-5089 void rendersStreamableReturnTypeForAggregation() throws NoSuchMethodException {