From 5643799128477e831487874501817db6bba4f2d0 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Tue, 26 Sep 2017 10:01:29 +0200 Subject: [PATCH] DATAKV-196 - Polishing. Update JavaDoc and fix trailing whitespaces. Add and use dedicated factory for caching constructors for and instantiating AbstractQueryCreator. Original Pull Request: #27 --- ...ValueRepositoryConfigurationExtension.java | 11 +-- .../query/KeyValuePartTreeQuery.java | 85 ++++++++++++++----- 2 files changed, 69 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/springframework/data/keyvalue/repository/config/KeyValueRepositoryConfigurationExtension.java b/src/main/java/org/springframework/data/keyvalue/repository/config/KeyValueRepositoryConfigurationExtension.java index 83375c4..96c0f60 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/config/KeyValueRepositoryConfigurationExtension.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/config/KeyValueRepositoryConfigurationExtension.java @@ -105,7 +105,7 @@ public abstract class KeyValueRepositoryConfigurationExtension extends Repositor * Detects the query creator type to be used for the factory to set. Will lookup a {@link QueryCreatorType} annotation * on the {@code @Enable}-annotation or use {@link SpelQueryCreator} if not found. * - * @param config + * @param config must not be {@literal null}. * @return */ private static Class getQueryCreatorType(AnnotationRepositoryConfigurationSource config) { @@ -190,8 +190,9 @@ public abstract class KeyValueRepositoryConfigurationExtension extends Repositor * Returns the {@link org.springframework.data.keyvalue.core.KeyValueTemplate} bean name to potentially register a * default {@link org.springframework.data.keyvalue.core.KeyValueTemplate} bean if no bean is registered with the * returned name. - * - * @return the default {@link org.springframework.data.keyvalue.core.KeyValueTemplate} bean name. + * + * @return the default {@link org.springframework.data.keyvalue.core.KeyValueTemplate} bean name. Never + * {@literal null}. * @see #getDefaultKeyValueTemplateBeanDefinition(RepositoryConfigurationSource) */ protected abstract String getDefaultKeyValueTemplateRef(); @@ -200,8 +201,8 @@ public abstract class KeyValueRepositoryConfigurationExtension extends Repositor * Returns the {@link org.springframework.data.mapping.context.MappingContext} bean name to potentially register a * default mapping context bean if no bean is registered with the returned name. Defaults to * {@link MAPPING_CONTEXT_BEAN_NAME}. - * - * @return the {@link org.springframework.data.mapping.context.MappingContext} bean name. + * + * @return the {@link org.springframework.data.mapping.context.MappingContext} bean name. Never {@literal null}. * @since 2.0 */ protected String getMappingContextBeanRef() { diff --git a/src/main/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQuery.java b/src/main/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQuery.java index 34a828f..d9803c7 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQuery.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQuery.java @@ -52,7 +52,7 @@ public class KeyValuePartTreeQuery implements RepositoryQuery { private final EvaluationContextProvider evaluationContextProvider; private final QueryMethod queryMethod; private final KeyValueOperations keyValueOperations; - private final Class> queryCreator; + private final QueryCreatorFactory, ?>> queryCreatorFactory; /** * Creates a new {@link KeyValuePartTreeQuery} for the given {@link QueryMethod}, {@link EvaluationContextProvider}, @@ -66,15 +66,33 @@ public class KeyValuePartTreeQuery implements RepositoryQuery { public KeyValuePartTreeQuery(QueryMethod queryMethod, EvaluationContextProvider evaluationContextProvider, KeyValueOperations keyValueOperations, Class> queryCreator) { + this(queryMethod, evaluationContextProvider, keyValueOperations, + new ConstructorCachingQueryCreatorFactory(queryCreator)); + } + + /** + * Creates a new {@link KeyValuePartTreeQuery} for the given {@link QueryMethod}, {@link EvaluationContextProvider}, + * {@link KeyValueOperations} using the given {@link QueryCreatorFactory} producing the {@link AbstractQueryCreator} + * in charge of altering the query. + * + * @param queryMethod must not be {@literal null}. + * @param evaluationContextProvider must not be {@literal null}. + * @param keyValueOperations must not be {@literal null}. + * @param queryCreatorFactory must not be {@literal null}. + * @since 2.0 + */ + public KeyValuePartTreeQuery(QueryMethod queryMethod, EvaluationContextProvider evaluationContextProvider, + KeyValueOperations keyValueOperations, QueryCreatorFactory queryCreatorFactory) { + Assert.notNull(queryMethod, "Query method must not be null!"); Assert.notNull(evaluationContextProvider, "EvaluationContextprovider must not be null!"); Assert.notNull(keyValueOperations, "KeyValueOperations must not be null!"); - Assert.notNull(queryCreator, "QueryCreator type must not be null!"); + Assert.notNull(queryCreatorFactory, "QueryCreatorFactory type must not be null!"); this.queryMethod = queryMethod; this.keyValueOperations = keyValueOperations; this.evaluationContextProvider = evaluationContextProvider; - this.queryCreator = queryCreator; + this.queryCreatorFactory = queryCreatorFactory; } /* @@ -187,7 +205,8 @@ public class KeyValuePartTreeQuery implements RepositoryQuery { PartTree tree = new PartTree(getQueryMethod().getName(), getQueryMethod().getEntityInformation().getJavaType()); - AbstractQueryCreator, ?> queryCreator = createQueryCreator(tree, accessor); + AbstractQueryCreator, ?> queryCreator = queryCreatorFactory.queryCreatorFor(tree, + accessor); KeyValueQuery query = queryCreator.createQuery(); @@ -197,24 +216,6 @@ public class KeyValuePartTreeQuery implements RepositoryQuery { return query; } - /** - * Constructs a {@link AbstractQueryCreator} for repository query creation. Subclasses may override this method to - * customize query creator construction. - * - * @param tree must not be {@literal null}. - * @param accessor must not be {@literal null}. - * @return the {@link AbstractQueryCreator} object. - * @since 2.0 - */ - protected AbstractQueryCreator, ?> createQueryCreator(PartTree tree, - ParameterAccessor accessor) { - - Constructor> constructor = ClassUtils.getConstructorIfAvailable(queryCreator, - PartTree.class, ParameterAccessor.class); - - return (AbstractQueryCreator, ?>) BeanUtils.instantiateClass(constructor, tree, accessor); - } - /* * (non-Javadoc) * @see org.springframework.data.repository.query.RepositoryQuery#getQueryMethod() @@ -223,4 +224,44 @@ public class KeyValuePartTreeQuery implements RepositoryQuery { public QueryMethod getQueryMethod() { return queryMethod; } + + /** + * Factory class for obtaining {@link AbstractQueryCreator} instances for a given {@link PartTree} and + * {@link ParameterAccessor}. + * + * @author Christoph Strobl + * @since 2.0 + */ + public interface QueryCreatorFactory { + + T queryCreatorFor(PartTree partTree, ParameterAccessor accessor); + } + + /** + * {@link QueryCreatorFactory} implementation instantiating {@link AbstractQueryCreator} via reflection. Looks up and + * caches the constructor on creation. + * + * @author Christoph Strobl + * @since 2.0 + */ + private static class ConstructorCachingQueryCreatorFactory + implements QueryCreatorFactory, ?>> { + + private final Class type; + private final @Nullable Constructor> constructor; + + ConstructorCachingQueryCreatorFactory(Class> type) { + + this.type = type; + this.constructor = ClassUtils.getConstructorIfAvailable(type, PartTree.class, ParameterAccessor.class); + } + + @Override + public AbstractQueryCreator, ?> queryCreatorFor(PartTree partTree, ParameterAccessor accessor) { + + Assert.state(constructor != null, + () -> String.format("No constructor (PartTree, ParameterAccessor) could be found on type %s!", type)); + return (AbstractQueryCreator, ?>) BeanUtils.instantiateClass(constructor, partTree, accessor); + } + } }