diff --git a/src/main/java/org/springframework/data/repository/core/RepositoryInformationSupport.java b/src/main/java/org/springframework/data/repository/core/RepositoryInformationSupport.java index eb46371c1e..ddc85065ff 100644 --- a/src/main/java/org/springframework/data/repository/core/RepositoryInformationSupport.java +++ b/src/main/java/org/springframework/data/repository/core/RepositoryInformationSupport.java @@ -19,8 +19,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.Collections; -import java.util.HashSet; +import java.util.Arrays; import java.util.Set; import java.util.function.Supplier; @@ -43,6 +42,7 @@ public abstract class RepositoryInformationSupport implements RepositoryInformat private final Supplier metadata; private final Supplier> repositoryBaseClass; + private final Supplier queryMethods; public RepositoryInformationSupport(Supplier metadata, Supplier> repositoryBaseClass) { @@ -51,25 +51,12 @@ public RepositoryInformationSupport(Supplier metadata, Suppl this.metadata = Lazy.of(metadata); this.repositoryBaseClass = Lazy.of(repositoryBaseClass); + this.queryMethods = Lazy.of(this::calculateQueryMethods); } @Override public Streamable getQueryMethods() { - - Set result = new HashSet<>(); - - for (Method method : getRepositoryInterface().getMethods()) { - method = ClassUtils.getMostSpecificMethod(method, getRepositoryInterface()); - if (isQueryMethodCandidate(method)) { - result.add(method); - } - } - - return Streamable.of(Collections.unmodifiableSet(result)); - } - - private RepositoryMetadata getMetadata() { - return metadata.get(); + return queryMethods.get().methods; } @Override @@ -139,21 +126,12 @@ public TypeInformation getIdTypeInformation() { @Override public boolean hasCustomMethod() { + return queryMethods.get().hasCustomMethod; + } - Class repositoryInterface = getRepositoryInterface(); - - // No detection required if no typing interface was configured - if (isGenericRepositoryInterface(repositoryInterface)) { - return false; - } - - for (Method method : repositoryInterface.getMethods()) { - if (isCustomMethod(method) && !isBaseClassMethod(method)) { - return true; - } - } - - return false; + @Override + public boolean hasQueryMethods() { + return queryMethods.get().hasQueryMethod; } /** @@ -178,4 +156,52 @@ protected boolean isQueryMethodCandidate(Method method) { && !Modifier.isStatic(method.getModifiers()) // && (isQueryAnnotationPresentOn(method) || !isCustomMethod(method) && !isBaseClassMethod(method)); } + + private RepositoryMetadata getMetadata() { + return metadata.get(); + } + + private final DefaultQueryMethods calculateQueryMethods() { + + Class repositoryInterface = getRepositoryInterface(); + + return new DefaultQueryMethods(Streamable.of(Arrays.stream(repositoryInterface.getMethods()) + .map(it -> ClassUtils.getMostSpecificMethod(it, repositoryInterface)) + .filter(this::isQueryMethodCandidate) + .toList()), calculateHasCustomMethod(repositoryInterface)); + } + + private final boolean calculateHasCustomMethod(Class repositoryInterface) { + + // No detection required if no typing interface was configured + if (isGenericRepositoryInterface(repositoryInterface)) { + return false; + } + + for (Method method : repositoryInterface.getMethods()) { + if (isCustomMethod(method) && !isBaseClassMethod(method)) { + return true; + } + } + + return false; + } + + /** + * Information about query methods to allow canonical computation and reuse of that information. + * + * @author Oliver Drotbohm + */ + private static class DefaultQueryMethods { + + private final Streamable methods; + private final boolean hasCustomMethod, hasQueryMethod; + + DefaultQueryMethods(Streamable methods, boolean hasCustomMethod) { + + this.methods = methods; + this.hasCustomMethod = hasCustomMethod; + this.hasQueryMethod = !methods.isEmpty(); + } + } }