DATACASS-335 - Adapt to new changes in reactive repository configuration.

We now use the newly introduced ….useRepositoryConfiguration(…) in the module specific RepositoryConfigurationExtension implementations to distinguish between reactive and non-reactive repositories.

Removed RepositoryType class as it was only used by the previous repository type detection.

Moved to new base class for reactive repository factories.
This commit is contained in:
Mark Paluch
2016-11-17 21:10:00 +01:00
parent 9e115bef2f
commit 636c49e058
4 changed files with 17 additions and 245 deletions

View File

@@ -13,30 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.cassandra.repository.config;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.cassandra.config.xml.ParsingUtils;
import org.springframework.core.io.ResourceLoader;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.cassandra.config.DefaultBeanNames;
import org.springframework.data.cassandra.mapping.Table;
import org.springframework.data.cassandra.repository.CassandraRepository;
import org.springframework.data.cassandra.repository.support.CassandraRepositoryFactoryBean;
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
import org.springframework.data.repository.config.RepositoryConfiguration;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
import org.springframework.data.repository.config.RepositoryConfigurationSource;
import org.springframework.data.repository.config.XmlRepositoryConfigurationSource;
import org.springframework.data.repository.util.ReactiveWrappers;
import org.springframework.util.ClassUtils;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
@@ -116,49 +109,12 @@ public class CassandraRepositoryConfigurationExtension extends RepositoryConfigu
return Collections.singleton(CassandraRepository.class);
}
/**
* @inheritDoc
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#useRepositoryConfiguration(org.springframework.data.repository.core.RepositoryMetadata)
*/
@Override
public <T extends RepositoryConfigurationSource> Collection<RepositoryConfiguration<T>> getRepositoryConfigurations(
T configSource, ResourceLoader loader, boolean strictMatchesOnly) {
Collection<RepositoryConfiguration<T>> repositoryConfigurations =
super.getRepositoryConfigurations(configSource, loader, strictMatchesOnly);
return (ReactiveWrappers.isAvailable() ? filter(repositoryConfigurations, loader) : repositoryConfigurations);
}
/* (non-Javadoc) */
private <T extends RepositoryConfigurationSource> Collection<RepositoryConfiguration<T>> filter(
Collection<RepositoryConfiguration<T>> repositoryConfigurations, ResourceLoader loader) {
return repositoryConfigurations.stream().filter(
configuration -> isNonReactiveRepository(configuration, loader)).collect(Collectors.toList());
}
/* (non-Javadoc) */
private boolean isNonReactiveRepository(RepositoryConfiguration<?> repositoryConfiguration, ResourceLoader loader) {
return !RepositoryType.isReactiveRepository(loadRepositoryInterface(repositoryConfiguration, loader));
}
/**
* TODO replace with {@link org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#loadRepositoryInterface(RepositoryConfiguration, ResourceLoader)}
* Loads the Repository interface specified in the given {@link RepositoryConfiguration} using
* the given {@link ResourceLoader}.
*
* @param configuration must not be {@literal null}.
* @param loader must not be {@literal null}.
* @return the Repository interface.
* @throws InvalidDataAccessApiUsageException if the Repository interface could not loaded.
*/
private Class<?> loadRepositoryInterface(RepositoryConfiguration<?> configuration, ResourceLoader loader) {
try {
return ClassUtils.forName(configuration.getRepositoryInterface(), loader.getClassLoader());
}
catch (ClassNotFoundException | LinkageError e) {
throw new InvalidDataAccessApiUsageException(String.format(
"Could not find Repository type [%s]", configuration.getRepositoryInterface()), e);
}
protected boolean useRepositoryConfiguration(RepositoryMetadata metadata) {
return !metadata.isReactiveRepository();
}
}

View File

@@ -13,27 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.cassandra.repository.config;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.core.io.ResourceLoader;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.cassandra.mapping.Table;
import org.springframework.data.cassandra.repository.ReactiveCassandraRepository;
import org.springframework.data.cassandra.repository.support.ReactiveCassandraRepositoryFactoryBean;
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
import org.springframework.data.repository.config.RepositoryConfiguration;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
import org.springframework.data.repository.config.RepositoryConfigurationSource;
import org.springframework.data.repository.config.XmlRepositoryConfigurationSource;
import org.springframework.util.ClassUtils;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.util.StringUtils;
/**
@@ -42,7 +32,7 @@ import org.springframework.util.StringUtils;
* @author Mark Paluch
* @since 2.0
*/
public class ReactiveCassandraRepositoryConfigurationExtension extends RepositoryConfigurationExtensionSupport {
public class ReactiveCassandraRepositoryConfigurationExtension extends CassandraRepositoryConfigurationExtension {
/**
* @inheritDoc
@@ -52,14 +42,6 @@ public class ReactiveCassandraRepositoryConfigurationExtension extends Repositor
return "Reactive Cassandra";
}
/**
* @inheritDoc
*/
@Override
protected String getModulePrefix() {
return "cassandra";
}
/**
* @inheritDoc
*/
@@ -68,12 +50,6 @@ public class ReactiveCassandraRepositoryConfigurationExtension extends Repositor
return ReactiveCassandraRepositoryFactoryBean.class.getName();
}
/**
* @inheritDoc
*/
@Override
public void postProcess(BeanDefinitionBuilder builder, XmlRepositoryConfigurationSource config) {}
/**
* @inheritDoc
*/
@@ -87,14 +63,6 @@ public class ReactiveCassandraRepositoryConfigurationExtension extends Repositor
}
}
/**
* @inheritDoc
*/
@Override
protected Collection<Class<? extends Annotation>> getIdentifyingAnnotations() {
return Collections.singleton(Table.class);
}
/**
* @inheritDoc
*/
@@ -103,38 +71,11 @@ public class ReactiveCassandraRepositoryConfigurationExtension extends Repositor
return Collections.singleton(ReactiveCassandraRepository.class);
}
/**
* @inheritDoc
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#useRepositoryConfiguration(org.springframework.data.repository.core.RepositoryMetadata)
*/
@Override
public <T extends RepositoryConfigurationSource> Collection<RepositoryConfiguration<T>> getRepositoryConfigurations(
T configSource, ResourceLoader loader, boolean strictMatchesOnly) {
Collection<RepositoryConfiguration<T>> repositoryConfigurations =
super.getRepositoryConfigurations(configSource, loader, strictMatchesOnly);
return repositoryConfigurations.stream()
.filter(configuration -> RepositoryType.isReactiveRepository(loadRepositoryInterface(configuration, loader)))
.collect(Collectors.toList());
}
/**
* TODO replace with {@link org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#loadRepositoryInterface(RepositoryConfiguration, ResourceLoader)}
* Loads the Repository interface specified in the given {@link RepositoryConfiguration} using
* the given {@link ResourceLoader}.
*
* @param configuration must not be {@literal null}.
* @param loader must not be {@literal null}.
* @return the Repository interface.
* @throws InvalidDataAccessApiUsageException if the Repository interface could not loaded.
*/
private Class<?> loadRepositoryInterface(RepositoryConfiguration<?> configuration, ResourceLoader loader) {
try {
return ClassUtils.forName(configuration.getRepositoryInterface(), loader.getClassLoader());
}
catch (ClassNotFoundException | LinkageError e) {
throw new InvalidDataAccessApiUsageException(String.format(
"Could not find Repository type [%s]", configuration.getRepositoryInterface()), e);
}
protected boolean useRepositoryConfiguration(RepositoryMetadata metadata) {
return metadata.isReactiveRepository();
}
}

View File

@@ -1,70 +0,0 @@
/*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.cassandra.repository.config;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.springframework.data.repository.util.ReactiveWrappers;
import org.springframework.util.ReflectionUtils;
import lombok.experimental.UtilityClass;
/**
* Utility class to discover whether a repository interface uses reactive wrapper types.
*
* @author Mark Paluch
* @since 2.0
*/
@UtilityClass
class RepositoryType {
/**
* Check whether {@code repositoryInterface} uses reactive wrapper types as return type or parameter types in its
* methods.
*
* @param repositoryInterface must not be {@literal null}.
* @return {@literal true} if the {@code repositoryInterface} uses reactive wrapper types.
* @see ReactiveWrappers
* @see ReactiveWrappers#isAvailable()
*/
public static boolean isReactiveRepository(Class<?> repositoryInterface) {
if (repositoryInterface == null || !ReactiveWrappers.isAvailable()) {
return false;
}
List<Method> reactiveMethods = new ArrayList<>();
ReflectionUtils.doWithMethods(repositoryInterface, reactiveMethods::add, RepositoryType::usesReactiveWrappers);
return !reactiveMethods.isEmpty();
}
private static boolean usesReactiveWrappers(Method method) {
if (ReactiveWrappers.supports(method.getReturnType())) {
return true;
}
for (Class<?> parameterType : method.getParameterTypes()) {
if (ReactiveWrappers.supports(parameterType)) {
return true;
}
}
return false;
}
}

View File

@@ -13,15 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.cassandra.repository.support;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.reactivestreams.Publisher;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.cassandra.core.ReactiveCassandraOperations;
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
@@ -34,16 +30,13 @@ import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.core.support.ReactiveRepositoryFactorySupport;
import org.springframework.data.repository.query.EvaluationContextProvider;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.util.ReactiveWrapperConverters;
import org.springframework.data.repository.util.ReactiveWrappers;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Factory to create {@link org.springframework.data.cassandra.repository.ReactiveCassandraRepository} instances.
@@ -51,7 +44,7 @@ import org.springframework.util.ClassUtils;
* @author Mark Paluch
* @since 2.0
*/
public class ReactiveCassandraRepositoryFactory extends RepositoryFactorySupport {
public class ReactiveCassandraRepositoryFactory extends ReactiveRepositoryFactorySupport {
private static final SpelExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
@@ -87,8 +80,7 @@ public class ReactiveCassandraRepositoryFactory extends RepositoryFactorySupport
@Override
protected Object getTargetRepository(RepositoryInformation information) {
CassandraEntityInformation<?, Serializable> entityInformation =
getEntityInformation(information.getDomainType());
CassandraEntityInformation<?, Serializable> entityInformation = getEntityInformation(information.getDomainType());
return getTargetRepositoryViaReflection(information, entityInformation, operations);
}
@@ -102,53 +94,6 @@ public class ReactiveCassandraRepositoryFactory extends RepositoryFactorySupport
return new CassandraQueryLookupStrategy(operations, evaluationContextProvider, mappingContext);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#validate(org.springframework.data.repository.core.RepositoryMetadata)
*/
@Override
protected void validate(RepositoryMetadata repositoryMetadata) {
if (!ReactiveWrappers.isAvailable()) {
throw new InvalidDataAccessApiUsageException(
String.format("Cannot implement Repository %s without reactive library support.",
repositoryMetadata.getRepositoryInterface().getName()));
}
Arrays.stream(repositoryMetadata.getRepositoryInterface().getMethods())
.forEach(ReactiveCassandraRepositoryFactory::validate);
}
/**
* Reactive Cassandra support requires reactive wrapper support. If return type/parameters are reactive wrapper types,
* then it's required to be able to convert these into Publisher.
*
* @param method the method to validate.
*/
private static void validate(Method method) {
if (ReactiveWrappers.supports(method.getReturnType())
&& !ClassUtils.isAssignable(Publisher.class, method.getReturnType())) {
if (!ReactiveWrapperConverters.supports(method.getReturnType())) {
throw new InvalidDataAccessApiUsageException(
String.format("No reactive type converter found for type %s used in %s, method %s.",
method.getReturnType().getName(), method.getDeclaringClass().getName(), method));
}
}
Arrays.stream(method.getParameterTypes()) //
.filter(ReactiveWrappers::supports) //
.filter(parameterType -> !ClassUtils.isAssignable(Publisher.class, parameterType)) //
.filter(parameterType -> !ReactiveWrapperConverters.supports(parameterType)) //
.forEach(parameterType -> {
throw new InvalidDataAccessApiUsageException(
String.format("No reactive type converter found for type %s used in %s, method %s.",
parameterType.getName(), method.getDeclaringClass().getName(), method));
});
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getEntityInformation(java.lang.Class)
@@ -159,7 +104,7 @@ public class ReactiveCassandraRepositoryFactory extends RepositoryFactorySupport
if (entity == null) {
throw new MappingException(
String.format("Could not lookup mapping metadata for domain class %s!", domainClass.getName()));
String.format("Could not lookup mapping metadata for domain class %s!", domainClass.getName()));
}
return new MappingCassandraEntityInformation<>((CassandraPersistentEntity<T>) entity, operations.getConverter());