From 646d13d1e2cecb48e779da7570d7a46fe6b4cde2 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Fri, 3 Mar 2023 11:06:09 +0200 Subject: [PATCH] Support multiple levels of repository interfaces in Spring Data JPA Closes: #31570 --- .../generate/DerivedMethodsAdder.java | 20 ++++++++++++++----- .../it/spring/data/jpa/ByPassHolder.java | 6 ++++++ ...itory.java => BypassHolderRepository.java} | 3 ++- .../data/jpa/IntermediatePostRepository.java | 12 +++++++++++ .../io/quarkus/it/spring/data/jpa/Post.java | 2 +- .../it/spring/data/jpa/PostRepository.java | 7 +------ 6 files changed, 37 insertions(+), 13 deletions(-) create mode 100644 integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/ByPassHolder.java rename integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/{IntermediateRepository.java => BypassHolderRepository.java} (72%) create mode 100644 integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/IntermediatePostRepository.java diff --git a/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/generate/DerivedMethodsAdder.java b/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/generate/DerivedMethodsAdder.java index 133b8b2f1cb68..a21110370604e 100644 --- a/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/generate/DerivedMethodsAdder.java +++ b/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/generate/DerivedMethodsAdder.java @@ -6,8 +6,10 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Consumer; import jakarta.transaction.Transactional; @@ -56,7 +58,7 @@ public DerivedMethodsAdder(IndexView index, TypeBundle typeBundle, ClassOutput n public void add(ClassCreator classCreator, FieldDescriptor entityClassFieldDescriptor, String generatedClassName, ClassInfo repositoryClassInfo, ClassInfo entityClassInfo) { MethodNameParser methodNameParser = new MethodNameParser(entityClassInfo, index); - List repoMethods = new ArrayList<>(repositoryClassInfo.methods()); + LinkedHashSet repoMethods = new LinkedHashSet<>(repositoryClassInfo.methods()); // Remember custom return type methods: {resultType:[methodName]} Map> customResultTypes = new HashMap<>(3); @@ -64,10 +66,7 @@ public void add(ClassCreator classCreator, FieldDescriptor entityClassFieldDescr //As intermediate interfaces are supported for spring data repositories, we need to search the methods declared in such interfaced and add them to the methods to implement list for (DotName extendedInterface : repositoryClassInfo.interfaceNames()) { - if (GenerationUtil.isIntermediateRepository(extendedInterface, index)) { - List methods = index.getClassByName(extendedInterface).methods(); - repoMethods.addAll(methods); - } + addAllMethodOfIntermediateRepository(extendedInterface, repoMethods); } for (MethodInfo method : repoMethods) { if (method.annotation(DotNames.SPRING_DATA_QUERY) != null) { // handled by CustomQueryMethodsAdder @@ -288,6 +287,17 @@ public void add(ClassCreator classCreator, FieldDescriptor entityClassFieldDescr } } + private void addAllMethodOfIntermediateRepository(DotName interfaceDotName, Set result) { + if (GenerationUtil.isIntermediateRepository(interfaceDotName, index)) { + ClassInfo classInfo = index.getClassByName(interfaceDotName); + List methods = classInfo.methods(); + result.addAll(methods); + for (DotName superInterface : classInfo.interfaceNames()) { + addAllMethodOfIntermediateRepository(superInterface, result); + } + } + } + private void generateCustomResultTypes(DotName interfaceName, DotName implName, ClassInfo entityClassInfo, List queryMethods) { diff --git a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/ByPassHolder.java b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/ByPassHolder.java new file mode 100644 index 0000000000000..5d3192d4fcc95 --- /dev/null +++ b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/ByPassHolder.java @@ -0,0 +1,6 @@ +package io.quarkus.it.spring.data.jpa; + +public interface ByPassHolder { + + boolean isBypass(); +} diff --git a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/IntermediateRepository.java b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/BypassHolderRepository.java similarity index 72% rename from integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/IntermediateRepository.java rename to integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/BypassHolderRepository.java index 66bfb2b63ab43..c7665642dcde5 100644 --- a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/IntermediateRepository.java +++ b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/BypassHolderRepository.java @@ -6,7 +6,7 @@ import org.springframework.data.repository.NoRepositoryBean; @NoRepositoryBean -public interface IntermediateRepository extends JpaRepository { +public interface BypassHolderRepository extends JpaRepository { default public void doNothing() { } @@ -15,4 +15,5 @@ default public T findMandatoryById(ID id) { return findById(id).orElseThrow(() -> new IllegalStateException("not found: " + id)); } + Post findFirstByBypassTrue(); } diff --git a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/IntermediatePostRepository.java b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/IntermediatePostRepository.java new file mode 100644 index 0000000000000..7f2528a208182 --- /dev/null +++ b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/IntermediatePostRepository.java @@ -0,0 +1,12 @@ +package io.quarkus.it.spring.data.jpa; + +import java.time.ZonedDateTime; +import java.util.List; + +/** + * Used to ensure that entity relationships work correctly + */ +public interface IntermediatePostRepository extends BypassHolderRepository { + + List findByPostedBefore(ZonedDateTime zdt); +} diff --git a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/Post.java b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/Post.java index 4e921073643e4..8bae2cbac9c67 100644 --- a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/Post.java +++ b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/Post.java @@ -18,7 +18,7 @@ @Entity(name = "Post") @Table(name = "post") -public class Post { +public class Post implements ByPassHolder { @Id @SequenceGenerator(name = "postSeqGen", sequenceName = "postSeq", initialValue = 100, allocationSize = 1) diff --git a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PostRepository.java b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PostRepository.java index 610ee5d70f48a..13d4eeafe0660 100644 --- a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PostRepository.java +++ b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PostRepository.java @@ -1,16 +1,11 @@ package io.quarkus.it.spring.data.jpa; -import java.time.ZonedDateTime; import java.util.List; /** * Used to ensure that entity relationships work correctly */ -public interface PostRepository extends IntermediateRepository { - - Post findFirstByBypassTrue(); - - List findByPostedBefore(ZonedDateTime zdt); +public interface PostRepository extends IntermediatePostRepository { List findAllByOrganization(String organization);