diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/BasicQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/BasicQuery.java index b381a2159..212b5c7e3 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/BasicQuery.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/BasicQuery.java @@ -85,6 +85,21 @@ public class BasicQuery extends Query { this.sortObject = new Document(); } + /** + * Create a BasicQuery given a {@link Query}. The resulting query is a copy of {@link Query}. + * + * @param query the query to copy. + * @since 4.4 + */ + public BasicQuery(Query query) { + + super(query); + this.queryObject = query.getQueryObject(); + this.setFieldsObject(query.getFieldsObject()); + this.setSortObject(query.getSortObject()); + this.setMeta(query.getMeta()); + } + @Override public Query addCriteria(CriteriaDefinition criteria) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java index 2b307f15c..d79b22aef 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java @@ -79,6 +79,20 @@ public class Query implements ReadConcernAware, ReadPreferenceAware { private Optional collation = Optional.empty(); + Query(Query query) { + this.restrictedTypes = query.restrictedTypes; + this.fieldSpec = query.fieldSpec; + this.sort = query.sort; + this.limit = query.limit; + this.skip = query.skip; + this.keysetScrollPosition = query.keysetScrollPosition; + this.readConcern = query.readConcern; + this.readPreference = query.readPreference; + this.hint = query.hint; + this.meta = query.meta; + this.collation = query.collation; + } + /** * Static factory method to create a {@link Query} using the provided {@link CriteriaDefinition}. * diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/RepositoryRuntimeHints.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/RepositoryRuntimeHints.java index 8ed6ea66c..46e6c9044 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/RepositoryRuntimeHints.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/RepositoryRuntimeHints.java @@ -24,10 +24,6 @@ import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.aot.hint.TypeReference; import org.springframework.data.mongodb.aot.MongoAotPredicates; -import org.springframework.data.mongodb.aot.MongoAotReflectionHelper; -import org.springframework.data.mongodb.core.query.BasicQuery; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.data.mongodb.repository.query.QueryUtils; import org.springframework.data.mongodb.repository.support.CrudMethodMetadata; import org.springframework.data.mongodb.repository.support.QuerydslMongoPredicateExecutor; import org.springframework.data.mongodb.repository.support.ReactiveQuerydslMongoPredicateExecutor; @@ -49,8 +45,6 @@ class RepositoryRuntimeHints implements RuntimeHintsRegistrar { builder -> builder.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_METHODS)); - registerHintsForDefaultSorting(hints, classLoader); - if (isAopPresent(classLoader)) { // required for pushing ReadPreference,... into the default repository implementation @@ -99,13 +93,4 @@ class RepositoryRuntimeHints implements RuntimeHintsRegistrar { return ClassUtils.isPresent("org.springframework.aop.Pointcut", classLoader); } - private static void registerHintsForDefaultSorting(RuntimeHints hints, @Nullable ClassLoader classLoader) { - - List types = List.of(TypeReference.of(Query.class), // - TypeReference.of(QueryUtils.queryProxyType(Query.class, classLoader)), // - TypeReference.of(BasicQuery.class), // - TypeReference.of(QueryUtils.queryProxyType(BasicQuery.class, classLoader))); - - hints.reflection().registerTypes(types, MongoAotReflectionHelper::cglibProxyReflectionMemberAccess); - } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java index 52eef5834..61bfa0f7b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java @@ -20,6 +20,7 @@ import java.util.List; import org.bson.Document; import org.bson.codecs.configuration.CodecRegistry; + import org.springframework.data.mapping.model.SpELExpressionEvaluator; import org.springframework.data.mongodb.core.ExecutableFindOperation.ExecutableFind; import org.springframework.data.mongodb.core.ExecutableFindOperation.FindWithQuery; @@ -155,7 +156,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery { * @since 4.2 */ private Query applyAnnotatedReadPreferenceIfPresent(Query query) { - + if (!method.hasAnnotatedReadPreference()) { return query; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/QueryUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/QueryUtils.java index c7cb84d09..c6ad7a634 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/QueryUtils.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/QueryUtils.java @@ -18,17 +18,15 @@ package org.springframework.data.mongodb.repository.query; import java.util.Arrays; import java.util.List; -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.bson.Document; -import org.springframework.aop.framework.ProxyFactory; + +import org.springframework.data.mongodb.core.query.BasicQuery; import org.springframework.data.mongodb.core.query.Collation; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; import org.springframework.expression.ExpressionParser; -import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; @@ -41,7 +39,7 @@ import org.springframework.util.ClassUtils; * @since 2.1 * @currentRead Assassin's Apprentice - Robin Hobb */ -public class QueryUtils { +class QueryUtils { protected static final Log LOGGER = LogFactory.getLog(QueryUtils.class); @@ -53,25 +51,19 @@ public class QueryUtils { * @param defaultSort the default sort expression to apply to the query. * @return the query having the given {@code sort} applied. */ - public static Query decorateSort(Query query, Document defaultSort) { + static Query decorateSort(Query query, Document defaultSort) { if (defaultSort.isEmpty()) { return query; } - ProxyFactory factory = prepareQueryProxy(query.getClass(), defaultSort); - factory.setTarget(query); - return (Query) factory.getProxy(query.getClass().getClassLoader()); - } + BasicQuery defaultSortQuery = query instanceof BasicQuery bq ? bq : new BasicQuery(query); - /** - * Decorate {@link Query} and add a default sort expression to the given {@link Query}. Attributes of the given - * {@code sort} may be overwritten by the sort explicitly defined by the {@link Query} itself. - * - * @param classLoader the {@link ClassLoader} to use for generating the proxy type with. - */ - public static Class queryProxyType(Class baseType, ClassLoader classLoader) { - return prepareQueryProxy(baseType, new Document()).getProxyClass(classLoader); + Document combinedSort = new Document(defaultSort); + combinedSort.putAll(defaultSortQuery.getSortObject()); + defaultSortQuery.setSortObject(combinedSort); + + return defaultSortQuery; } /** @@ -116,13 +108,13 @@ public class QueryUtils { */ static int indexOfAssignableParameter(Class type, List> parameters) { - if(parameters.isEmpty()) { + if (parameters.isEmpty()) { return -1; } int i = 0; - for(Class parameterType : parameters) { - if(ClassUtils.isAssignable(type, parameterType)) { + for (Class parameterType : parameters) { + if (ClassUtils.isAssignable(type, parameterType)) { return i; } i++; @@ -130,34 +122,4 @@ public class QueryUtils { return -1; } - private static ProxyFactory prepareQueryProxy(Class query, Document defaultSort) { - - ProxyFactory factory = new ProxyFactory(); - factory.setTargetClass(query); - factory.addAdvice(new DefaultSortingInterceptor(defaultSort)); - factory.setInterfaces(new Class[0]); - return factory; - } - - static class DefaultSortingInterceptor implements MethodInterceptor { - - private final Document defaultSort; - - public DefaultSortingInterceptor(Document defaultSort) { - this.defaultSort = defaultSort; - } - - @Nullable - @Override - public Object invoke(@NonNull MethodInvocation invocation) throws Throwable { - - if (!invocation.getMethod().getName().equals("getSortObject")) { - return invocation.proceed(); - } - - Document combinedSort = new Document(defaultSort); - combinedSort.putAll((Document) invocation.proceed()); - return combinedSort; - } - } }