diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoParameters.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoParameters.java index 257d8d191..1f66d5b77 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoParameters.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoParameters.java @@ -15,6 +15,7 @@ */ package org.springframework.data.mongodb.repository.query; +import java.io.Serializable; import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; @@ -22,6 +23,9 @@ import java.util.List; import org.springframework.core.MethodParameter; import org.springframework.data.domain.Range; import org.springframework.data.geo.Distance; +import org.springframework.data.geo.GeoPage; +import org.springframework.data.geo.GeoResult; +import org.springframework.data.geo.GeoResults; import org.springframework.data.geo.Point; import org.springframework.data.mongodb.core.query.Collation; import org.springframework.data.mongodb.core.query.TextCriteria; @@ -44,6 +48,9 @@ import org.springframework.lang.Nullable; */ public class MongoParameters extends Parameters { + private static final List> GEO_NEAR_RESULTS = Arrays.asList(GeoResult.class, + GeoResults.class, GeoPage.class); + private final int rangeIndex; private final int maxDistanceIndex; private final @Nullable Integer fullTextIndex; @@ -56,7 +63,17 @@ public class MongoParameters extends Parameters * Creates a new {@link MongoParameters} instance from the given {@link Method} and {@link MongoQueryMethod}. * * @param parametersSource must not be {@literal null}. - * @param isGeoNearMethod indicate if this is a geo spatial query method + * @since 4.5 + */ + public MongoParameters(ParametersSource parametersSource) { + this(parametersSource, isGeoNearQuery(parametersSource.getMethod())); + } + + /** + * Creates a new {@link MongoParameters} instance from the given {@link Method} and {@link MongoQueryMethod}. + * + * @param parametersSource must not be {@literal null}. + * @param isGeoNearMethod indicate if this is a geo-spatial query method */ public MongoParameters(ParametersSource parametersSource, boolean isGeoNearMethod) { this(parametersSource, new NearIndex(parametersSource, isGeoNearMethod)); @@ -104,6 +121,24 @@ public class MongoParameters extends Parameters this.domainType = domainType; } + static boolean isGeoNearQuery(Method method) { + + Class returnType = method.getReturnType(); + + for (Class type : GEO_NEAR_RESULTS) { + if (type.isAssignableFrom(returnType)) { + return true; + } + } + + if (Iterable.class.isAssignableFrom(returnType)) { + TypeInformation from = TypeInformation.fromReturnTypeOf(method); + return GeoResult.class.equals(from.getRequiredComponentType().getType()); + } + + return false; + } + static class NearIndex { private final @Nullable Integer nearIndex; diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java index dcfef7de0..d3fe22b4e 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java @@ -15,18 +15,13 @@ */ package org.springframework.data.mongodb.repository.query; -import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Function; import org.springframework.core.annotation.AnnotatedElementUtils; -import org.springframework.data.geo.GeoPage; -import org.springframework.data.geo.GeoResult; -import org.springframework.data.geo.GeoResults; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mongodb.core.annotation.Collation; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; @@ -65,15 +60,12 @@ import org.springframework.util.StringUtils; */ public class MongoQueryMethod extends QueryMethod { - @SuppressWarnings("unchecked") private static final List> GEO_NEAR_RESULTS = Arrays - .asList(GeoResult.class, GeoResults.class, GeoPage.class); - private final Method method; private final MappingContext, MongoPersistentProperty> mappingContext; private final Map, Optional> annotationCache; private @Nullable MongoEntityMetadata metadata; - private Lazy isModifying = Lazy.of(this::resolveModifyingQueryIndicators); + private final Lazy isModifying = Lazy.of(this::resolveModifyingQueryIndicators); /** * Creates a new {@link MongoQueryMethod} from the given {@link Method}. @@ -85,8 +77,22 @@ public class MongoQueryMethod extends QueryMethod { */ public MongoQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory projectionFactory, MappingContext, MongoPersistentProperty> mappingContext) { + this(method, metadata, projectionFactory, mappingContext, MongoParameters::new); + } + + /** + * Creates a new {@link MongoQueryMethod} from the given {@link Method}. + * + * @param method must not be {@literal null}. + * @param metadata must not be {@literal null}. + * @param projectionFactory must not be {@literal null}. + * @param mappingContext must not be {@literal null}. + */ + MongoQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory projectionFactory, + MappingContext, MongoPersistentProperty> mappingContext, + Function parametersFunction) { - super(method, metadata, projectionFactory); + super(method, metadata, projectionFactory, parametersFunction); Assert.notNull(mappingContext, "MappingContext must not be null"); @@ -95,11 +101,6 @@ public class MongoQueryMethod extends QueryMethod { this.annotationCache = new ConcurrentReferenceHashMap<>(); } - @Override - protected MongoParameters createParameters(ParametersSource parametersSource) { - return new MongoParameters(parametersSource, isGeoNearQuery(parametersSource.getMethod())); - } - /** * Returns whether the method has an annotated query. * @@ -186,25 +187,7 @@ public class MongoQueryMethod extends QueryMethod { * @return */ public boolean isGeoNearQuery() { - return isGeoNearQuery(this.method); - } - - private boolean isGeoNearQuery(Method method) { - - Class returnType = method.getReturnType(); - - for (Class type : GEO_NEAR_RESULTS) { - if (type.isAssignableFrom(returnType)) { - return true; - } - } - - if (Iterable.class.isAssignableFrom(returnType)) { - TypeInformation from = TypeInformation.fromReturnTypeOf(method); - return GeoResult.class.equals(from.getRequiredComponentType().getType()); - } - - return false; + return MongoParameters.isGeoNearQuery(this.method); } /** diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveMongoQueryMethod.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveMongoQueryMethod.java index 8df1ba487..16354c2ff 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveMongoQueryMethod.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveMongoQueryMethod.java @@ -15,8 +15,6 @@ */ package org.springframework.data.mongodb.repository.query; -import static org.springframework.data.repository.util.ClassUtils.*; - import java.lang.reflect.Method; import org.springframework.dao.InvalidDataAccessApiUsageException; @@ -31,10 +29,10 @@ import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import org.springframework.data.mongodb.repository.query.MongoParameters.MongoParameter; import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.repository.core.RepositoryMetadata; -import org.springframework.data.repository.query.ParametersSource; import org.springframework.data.repository.util.ReactiveWrapperConverters; import org.springframework.data.util.Lazy; import org.springframework.data.util.ReactiveWrappers; +import org.springframework.data.util.ReflectionUtils; import org.springframework.data.util.TypeInformation; import org.springframework.util.ClassUtils; @@ -64,18 +62,16 @@ public class ReactiveMongoQueryMethod extends MongoQueryMethod { public ReactiveMongoQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory projectionFactory, MappingContext, MongoPersistentProperty> mappingContext) { - super(method, metadata, projectionFactory, mappingContext); + super(method, metadata, projectionFactory, mappingContext, parametersSource -> { + return new MongoParameters(parametersSource, + MongoParameters.isGeoNearQuery(parametersSource.getMethod()) || isGeoNearQuery(parametersSource.getMethod())); + }); this.method = method; this.isCollectionQuery = Lazy.of(() -> (!(isPageQuery() || isSliceQuery() || isScrollQuery()) && ReactiveWrappers.isMultiValueType(metadata.getReturnType(method).getType()) || super.isCollectionQuery())); } - @Override - protected MongoParameters createParameters(ParametersSource parametersSource) { - return new MongoParameters(parametersSource, isGeoNearQuery(parametersSource.getMethod())); - } - @Override public boolean isCollectionQuery() { return isCollectionQuery.get(); @@ -86,7 +82,7 @@ public class ReactiveMongoQueryMethod extends MongoQueryMethod { return isGeoNearQuery(method); } - private boolean isGeoNearQuery(Method method) { + private static boolean isGeoNearQuery(Method method) { if (ReactiveWrappers.supports(method.getReturnType())) { TypeInformation from = TypeInformation.fromReturnTypeOf(method); @@ -130,7 +126,7 @@ public class ReactiveMongoQueryMethod extends MongoQueryMethod { @Override public void verify() { - if (hasParameterOfType(method, Pageable.class)) { + if (ReflectionUtils.hasParameterOfType(method, Pageable.class)) { TypeInformation returnType = TypeInformation.fromReturnTypeOf(method); @@ -139,7 +135,7 @@ public class ReactiveMongoQueryMethod extends MongoQueryMethod { && (PAGE_TYPE.isAssignableFrom(returnType.getRequiredComponentType()) || SLICE_TYPE.isAssignableFrom(returnType.getRequiredComponentType())); - if (hasParameterOfType(method, Sort.class)) { + if (ReflectionUtils.hasParameterOfType(method, Sort.class)) { throw new IllegalStateException(String.format("Method must not have Pageable *and* Sort parameter;" + " Use sorting capabilities on Pageable instead; Offending method: %s", method)); }