Skip to content

DATACMNS-836 - Add components to support reactive repositories. #177

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 35 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>1.13.0.BUILD-SNAPSHOT</version>
<version>2.0.0.DATACMNS-836-SNAPSHOT</version>

<name>Spring Data Core</name>

<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>1.9.0.BUILD-SNAPSHOT</version>
<version>2.0.0.BUILD-SNAPSHOT</version>
</parent>

<properties>
<dist.key>DATACMNS</dist.key>
<scala>2.11.7</scala>
<xmlbeam>1.4.8</xmlbeam>
<spring>5.0.0.BUILD-SNAPSHOT</spring>
</properties>

<dependencies>
Expand Down Expand Up @@ -96,6 +96,38 @@
<optional>true</optional>
</dependency>

<!-- Project Reactor -->

<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>${reactor}</version>
<optional>true</optional>
</dependency>

<!-- RxJava -->

<dependency>
<groupId>io.reactivex</groupId>
<artifactId>rxjava</artifactId>
<version>${rxjava}</version>
<optional>true</optional>
</dependency>

<dependency>
<groupId>io.reactivex</groupId>
<artifactId>rxjava-reactive-streams</artifactId>
<version>${rxjava-reactive-streams}</version>
<optional>true</optional>
</dependency>

<dependency>
<groupId>io.reactivex.rxjava2</groupId>
<artifactId>rxjava</artifactId>
<version>${rxjava2}</version>
<optional>true</optional>
</dependency>

<!-- Querydsl -->

<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public AnnotationRevisionMetadata(final Object entity, Class<? extends Annotatio
AnnotationDetectionFieldCallback revisionCallback = new AnnotationDetectionFieldCallback(
revisionTimeStampAnnotation);
ReflectionUtils.doWithFields(entity.getClass(), revisionCallback);
this.revisionDate = new DateTime(revisionCallback.getValue(entity));
this.revisionDate = new DateTime(revisionCallback.<Object> getValue(entity));
} else {
this.revisionDate = null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
* {@link #getModulePrefix()}). Stubs out the post-processing methods as they might not be needed by default.
*
* @author Oliver Gierke
* @author Mark Paluch
*/
public abstract class RepositoryConfigurationExtensionSupport implements RepositoryConfigurationExtension {

Expand Down Expand Up @@ -86,15 +87,25 @@ public <T extends RepositoryConfigurationSource> Collection<RepositoryConfigurat
for (BeanDefinition candidate : configSource.getCandidates(loader)) {

RepositoryConfiguration<T> configuration = getRepositoryConfiguration(candidate, configSource);
Class<?> repositoryInterface = loadRepositoryInterface(configuration, loader);

if (!strictMatchesOnly || configSource.usesExplicitFilters()) {
if (repositoryInterface == null) {
result.add(configuration);
continue;
}

Class<?> repositoryInterface = loadRepositoryInterface(configuration, loader);
RepositoryMetadata metadata = AbstractRepositoryMetadata.getMetadata(repositoryInterface);

if (!useRepositoryConfiguration(metadata)) {
continue;
}

if (repositoryInterface == null || isStrictRepositoryCandidate(repositoryInterface)) {
if (!strictMatchesOnly || configSource.usesExplicitFilters()) {
result.add(configuration);
continue;
}

if (isStrictRepositoryCandidate(metadata)) {
result.add(configuration);
}
}
Expand Down Expand Up @@ -245,7 +256,7 @@ protected <T extends RepositoryConfigurationSource> RepositoryConfiguration<T> g
}

/**
* Returns whether the given repository interface is a candidate for bean definition creation in the strict repository
* Returns whether the given repository metadata is a candidate for bean definition creation in the strict repository
* detection mode. The default implementation inspects the domain type managed for a set of well-known annotations
* (see {@link #getIdentifyingAnnotations()}). If none of them is found, the candidate is discarded. Implementations
* should make sure, the only return {@literal true} if they're really sure the interface handed to the method is
Expand All @@ -255,11 +266,10 @@ protected <T extends RepositoryConfigurationSource> RepositoryConfiguration<T> g
* @return
* @since 1.9
*/
protected boolean isStrictRepositoryCandidate(Class<?> repositoryInterface) {

RepositoryMetadata metadata = AbstractRepositoryMetadata.getMetadata(repositoryInterface);
protected boolean isStrictRepositoryCandidate(RepositoryMetadata metadata) {

Collection<Class<?>> types = getIdentifyingTypes();
Class<?> repositoryInterface = metadata.getRepositoryInterface();

for (Class<?> type : types) {
if (type.isAssignableFrom(repositoryInterface)) {
Expand All @@ -285,6 +295,16 @@ protected boolean isStrictRepositoryCandidate(Class<?> repositoryInterface) {
return false;
}

/**
* Return whether to use the configuration for the repository with the given metadata. Defaults to {@literal true}.
*
* @param metadata will never be {@literal null}.
* @return
*/
protected boolean useRepositoryConfiguration(RepositoryMetadata metadata) {
return true;
}

/**
* Loads the repository interface contained in the given {@link RepositoryConfiguration} using the given
* {@link ResourceLoader}.
Expand All @@ -300,9 +320,7 @@ private Class<?> loadRepositoryInterface(RepositoryConfiguration<?> configuratio

try {
return org.springframework.util.ClassUtils.forName(repositoryInterface, classLoader);
} catch (ClassNotFoundException e) {
LOGGER.warn(String.format(CLASS_LOADING_ERROR, getModuleName(), repositoryInterface, classLoader), e);
} catch (LinkageError e) {
} catch (ClassNotFoundException | LinkageError e) {
LOGGER.warn(String.format(CLASS_LOADING_ERROR, getModuleName(), repositoryInterface, classLoader), e);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2011-2015 the original author or authors.
* Copyright 2011-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.
Expand Down Expand Up @@ -83,4 +83,12 @@ public interface RepositoryMetadata {
* @since 1.11
*/
Set<Class<?>> getAlternativeDomainTypes();

/**
* Returns whether the repository is a reactive one, i.e. if it uses reactive types in one of its methods.
*
* @return
* @since 2.0
*/
boolean isReactiveRepository();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2011-2015 the original author or authors.
* Copyright 2011-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.
Expand All @@ -25,6 +25,7 @@
import org.springframework.data.repository.core.CrudMethods;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.util.QueryExecutionConverters;
import org.springframework.data.repository.util.ReactiveWrappers;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.ReflectionUtils;
import org.springframework.data.util.TypeInformation;
Expand Down Expand Up @@ -126,6 +127,15 @@ public Set<Class<?>> getAlternativeDomainTypes() {
return Collections.emptySet();
}

/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.RepositoryMetadata#isReactiveRepository()
*/
@Override
public boolean isReactiveRepository() {
return ReactiveWrappers.usesReactiveType(repositoryInterface);
}

/**
* Recursively unwraps well known wrapper types from the given {@link TypeInformation}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,12 @@
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
*/
class DefaultRepositoryInformation implements RepositoryInformation {

@SuppressWarnings("rawtypes") private static final TypeVariable<Class<Repository>>[] PARAMETERS = Repository.class
.getTypeParameters();
@SuppressWarnings("rawtypes") //
private static final TypeVariable<Class<Repository>>[] PARAMETERS = Repository.class.getTypeParameters();
private static final String DOMAIN_TYPE_NAME = PARAMETERS[0].getName();
private static final String ID_TYPE_NAME = PARAMETERS[1].getName();

Expand Down Expand Up @@ -334,42 +335,13 @@ public Set<Class<?>> getAlternativeDomainTypes() {
return metadata.getAlternativeDomainTypes();
}

/**
* Checks the given method's parameters to match the ones of the given base class method. Matches generic arguments
* agains the ones bound in the given repository interface.
*
* @param method
* @param baseClassMethod
* @return
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.RepositoryMetadata#isReactiveRepository()
*/
private boolean parametersMatch(Method method, Method baseClassMethod) {

Class<?>[] methodParameterTypes = method.getParameterTypes();
Type[] genericTypes = baseClassMethod.getGenericParameterTypes();
Class<?>[] types = baseClassMethod.getParameterTypes();

for (int i = 0; i < genericTypes.length; i++) {

Type genericType = genericTypes[i];
Class<?> type = types[i];
MethodParameter parameter = new MethodParameter(method, i);
Class<?> parameterType = resolveParameterType(parameter, metadata.getRepositoryInterface());

if (genericType instanceof TypeVariable<?>) {

if (!matchesGenericType((TypeVariable<?>) genericType, ResolvableType.forMethodParameter(parameter))) {
return false;
}

continue;
}

if (!type.isAssignableFrom(parameterType) || !type.equals(methodParameterTypes[i])) {
return false;
}
}

return true;
@Override
public boolean isReactiveRepository() {
return metadata.isReactiveRepository();
}

/**
Expand All @@ -381,7 +353,7 @@ private boolean parametersMatch(Method method, Method baseClassMethod) {
* @param parameterType must not be {@literal null}.
* @return
*/
private boolean matchesGenericType(TypeVariable<?> variable, ResolvableType parameterType) {
protected boolean matchesGenericType(TypeVariable<?> variable, ResolvableType parameterType) {

GenericDeclaration declaration = variable.getGenericDeclaration();

Expand All @@ -408,4 +380,42 @@ private boolean matchesGenericType(TypeVariable<?> variable, ResolvableType para

return false;
}

/**
* Checks the given method's parameters to match the ones of the given base class method. Matches generic arguments
* against the ones bound in the given repository interface.
*
* @param method
* @param baseClassMethod
* @return
*/
private boolean parametersMatch(Method method, Method baseClassMethod) {

Class<?>[] methodParameterTypes = method.getParameterTypes();
Type[] genericTypes = baseClassMethod.getGenericParameterTypes();
Class<?>[] types = baseClassMethod.getParameterTypes();

for (int i = 0; i < genericTypes.length; i++) {

Type genericType = genericTypes[i];
Class<?> type = types[i];
MethodParameter parameter = new MethodParameter(method, i);
Class<?> parameterType = resolveParameterType(parameter, metadata.getRepositoryInterface());

if (genericType instanceof TypeVariable<?>) {

if (!matchesGenericType((TypeVariable<?>) genericType, ResolvableType.forMethodParameter(parameter))) {
return false;
}

continue;
}

if (!type.isAssignableFrom(parameterType) || !type.equals(methodParameterTypes[i])) {
return false;
}
}

return true;
}
}
Loading