Skip to content

Commit a8a5cfc

Browse files
committed
Add support for returning Streamable from AOT repository methods.
Closes #4070
1 parent ba49ef4 commit a8a5cfc

File tree

5 files changed

+52
-2
lines changed

5 files changed

+52
-2
lines changed

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/aot/JpaCodeBlocks.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import org.springframework.data.repository.aot.generate.AotQueryMethodGenerationContext;
4949
import org.springframework.data.repository.aot.generate.MethodReturn;
5050
import org.springframework.data.support.PageableExecutionUtils;
51+
import org.springframework.data.util.Streamable;
5152
import org.springframework.javapoet.CodeBlock;
5253
import org.springframework.javapoet.CodeBlock.Builder;
5354
import org.springframework.javapoet.TypeName;
@@ -703,8 +704,12 @@ public CodeBlock build() {
703704
context.fieldNameOf(EntityManager.class));
704705

705706
if (collectionQuery) {
706-
builder.addStatement("return ($T) $L", List.class, context.localVariable("resultList"));
707707

708+
if (isStreamable(methodReturn)) {
709+
builder.addStatement("return ($1T) $1T.of($2L)", Streamable.class, context.localVariable("resultList"));
710+
} else {
711+
builder.addStatement("return ($T) $L", List.class, context.localVariable("resultList"));
712+
}
708713
} else if (returnCount) {
709714
builder.addStatement("return $T.valueOf($L.size())",
710715
ClassUtils.resolvePrimitiveIfNecessary(methodReturn.getActualReturnClass()),
@@ -770,7 +775,13 @@ public CodeBlock build() {
770775
} else {
771776

772777
if (queryMethod.isCollectionQuery()) {
773-
builder.addStatement("return ($T) $L.getResultList()", methodReturn.getTypeName(), queryVariableName);
778+
779+
if (isStreamable(methodReturn)) {
780+
builder.addStatement("return ($T) $T.of($L.getResultList())", methodReturn.getTypeName(),
781+
Streamable.class, queryVariableName);
782+
} else {
783+
builder.addStatement("return ($T) $L.getResultList()", methodReturn.getTypeName(), queryVariableName);
784+
}
774785
} else if (queryMethod.isStreamQuery()) {
775786
builder.addStatement("return ($T) $L.getResultStream()", methodReturn.getTypeName(), queryVariableName);
776787
} else if (queryMethod.isPageQuery()) {
@@ -800,6 +811,10 @@ public CodeBlock build() {
800811
return builder.build();
801812
}
802813

814+
private static boolean isStreamable(MethodReturn methodReturn) {
815+
return methodReturn.toClass().equals(Streamable.class);
816+
}
817+
803818
public static boolean returnsModifying(Class<?> returnType) {
804819

805820
return returnType == int.class || returnType == long.class || returnType == Integer.class

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
import org.springframework.data.jpa.repository.sample.UserRepository;
7676
import org.springframework.data.jpa.repository.sample.UserRepository.NameOnly;
7777
import org.springframework.data.jpa.util.DisabledOnHibernate;
78+
import org.springframework.data.util.Streamable;
7879
import org.springframework.test.context.ContextConfiguration;
7980
import org.springframework.test.context.junit.jupiter.SpringExtension;
8081
import org.springframework.transaction.annotation.Transactional;
@@ -2147,6 +2148,15 @@ void supportsJava8StreamForPageableMethod() {
21472148
}
21482149
}
21492150

2151+
@Test // GH-4070
2152+
void supportsStreamableForPageableMethod() {
2153+
2154+
flushTestUsers();
2155+
2156+
Streamable<User> users = repository.readStreamableAllByFirstnameNotNull(PageRequest.of(0, 2));
2157+
assertThat(users).hasSize(2);
2158+
}
2159+
21502160
@Test // DATAJPA-218
21512161
void findAllByExample() {
21522162

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/aot/JpaRepositoryContributorIntegrationTests.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.springframework.data.jpa.domain.sample.Role;
4040
import org.springframework.data.jpa.domain.sample.SpecialUser;
4141
import org.springframework.data.jpa.domain.sample.User;
42+
import org.springframework.data.util.Streamable;
4243
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
4344
import org.springframework.transaction.annotation.Transactional;
4445

@@ -199,6 +200,13 @@ void testDerivedFinderReturningListWithPageable() {
199200
assertThat(users).extracting(User::getEmailAddress).containsExactly("han@smuggler.net", "kylo@new-empire.com");
200201
}
201202

203+
@Test // GH-3830
204+
void testDerivedQueryMethodReturningStreamable() {
205+
206+
Streamable<User> users = fragment.findStreamableByLastnameStartingWith("S");
207+
assertThat(users).extracting(User::getEmailAddress).hasSize(4).contains("han@smuggler.net", "kylo@new-empire.com");
208+
}
209+
202210
@Test // GH-3830
203211
void testDerivedFinderReturningPage() {
204212

@@ -526,13 +534,22 @@ void testDerivedDeleteSingle() {
526534
assertThat(yodaShouldBeGone).isNull();
527535
}
528536

537+
@Test // GH-3830
538+
void shouldReturnStreamableDelete() {
539+
540+
Streamable<User> users = fragment.deleteStreamableByEmailAddress("yoda@jedi.org");
541+
542+
assertThat(users).hasSize(1);
543+
}
544+
529545
@Test // GH-3830
530546
void shouldOmitAnnotatedDeleteReturningDomainType() {
531547

532548
assertThatException().isThrownBy(() -> fragment.deleteAnnotatedQueryByEmailAddress("foo"))
533549
.withRootCauseInstanceOf(NoSuchMethodException.class);
534550
}
535551

552+
536553
@Test // GH-3830
537554
void shouldApplyModifying() {
538555

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/aot/UserRepository.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.springframework.data.jpa.repository.query.Procedure;
3737
import org.springframework.data.repository.CrudRepository;
3838
import org.springframework.data.repository.query.Param;
39+
import org.springframework.data.util.Streamable;
3940

4041
/**
4142
* @author Christoph Strobl
@@ -67,6 +68,8 @@ interface UserRepository extends CrudRepository<User, Integer> {
6768

6869
List<User> findByLastnameStartingWith(String lastname, Pageable page);
6970

71+
Streamable<User> findStreamableByLastnameStartingWith(String lastname);
72+
7073
Page<User> findPageOfUsersByLastnameStartingWith(String lastname, Pageable page);
7174

7275
Slice<User> findSliceOfUserByLastnameStartingWith(String lastname, Pageable page);
@@ -195,6 +198,8 @@ List<User> findWithParameterNameByLastnameStartingWithOrLastnameEndingWith(@Para
195198

196199
User deleteByEmailAddress(String username);
197200

201+
Streamable<User> deleteStreamableByEmailAddress(String username);
202+
198203
// cannot generate delete and return a domain object
199204
@Modifying
200205
@Query("delete from User u where u.emailAddress = ?1")

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import org.springframework.data.querydsl.ListQuerydslPredicateExecutor;
5454
import org.springframework.data.repository.CrudRepository;
5555
import org.springframework.data.repository.query.Param;
56+
import org.springframework.data.util.Streamable;
5657
import org.springframework.transaction.annotation.Transactional;
5758

5859
import com.querydsl.core.types.Predicate;
@@ -533,6 +534,8 @@ List<User> findUsersByFirstnameForSpELExpressionWithParameterIndexOnlyWithEntity
533534
@Query("select u from User u")
534535
Stream<User> streamAllPaged(Pageable pageable);
535536

537+
Streamable<User> readStreamableAllByFirstnameNotNull(Pageable pageable);
538+
536539
// DATAJPA-830
537540
List<User> findByLastnameNotContaining(String part);
538541

0 commit comments

Comments
 (0)