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:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user