Skip to content

Commit b1ed894

Browse files
committed
DATACOUCH-504 - Make sure reactive repositories can be used
This changeset fixes an issue where while blocking repositories would work properly, the reactive repositories won't. This has been an oversight in the transition before RC1.
1 parent 831fcaa commit b1ed894

18 files changed

+386
-74
lines changed

src/main/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfiguration.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.springframework.data.couchbase.core.convert.translation.TranslationService;
3939
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
4040
import org.springframework.data.couchbase.core.mapping.Document;
41+
import org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping;
4142
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
4243
import org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy;
4344
import org.springframework.data.mapping.model.FieldNamingStrategy;
@@ -116,7 +117,7 @@ public ReactiveCouchbaseTemplate reactiveCouchbaseTemplate(CouchbaseClientFactor
116117
return new ReactiveCouchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter);
117118
}
118119

119-
@Bean
120+
@Bean(name = BeanNames.COUCHBASE_OPERATIONS_MAPPING)
120121
public RepositoryOperationsMapping couchbaseRepositoryOperationsMapping(CouchbaseTemplate couchbaseTemplate) {
121122
// create a base mapping that associates all repositories to the default template
122123
RepositoryOperationsMapping baseMapping = new RepositoryOperationsMapping(couchbaseTemplate);
@@ -135,6 +136,25 @@ protected void configureRepositoryOperationsMapping(RepositoryOperationsMapping
135136
// NO_OP
136137
}
137138

139+
@Bean(name = BeanNames.REACTIVE_COUCHBASE_OPERATIONS_MAPPING)
140+
public ReactiveRepositoryOperationsMapping reactiveCouchbaseRepositoryOperationsMapping(ReactiveCouchbaseTemplate reactiveCouchbaseTemplate) {
141+
// create a base mapping that associates all repositories to the default template
142+
ReactiveRepositoryOperationsMapping baseMapping = new ReactiveRepositoryOperationsMapping(reactiveCouchbaseTemplate);
143+
// let the user tune it
144+
configureReactiveRepositoryOperationsMapping(baseMapping);
145+
return baseMapping;
146+
}
147+
148+
/**
149+
* In order to customize the mapping between repositories/entity types to couchbase templates, use the provided
150+
* mapping's api (eg. in order to have different buckets backing different repositories).
151+
*
152+
* @param mapping the default mapping (will associate all repositories to the default template).
153+
*/
154+
protected void configureReactiveRepositoryOperationsMapping(ReactiveRepositoryOperationsMapping mapping) {
155+
// NO_OP
156+
}
157+
138158
/**
139159
* Scans the mapping base package for classes annotated with {@link Document}.
140160
*

src/main/java/org/springframework/data/couchbase/repository/CouchbaseRepository.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,6 @@
3131
@NoRepositoryBean
3232
public interface CouchbaseRepository<T, ID> extends PagingAndSortingRepository<T, ID> {
3333

34-
/**
35-
* @return a reference to the underlying {@link CouchbaseOperations operation template}.
36-
*/
37-
CouchbaseOperations getCouchbaseOperations();
38-
3934
@Override
4035
List<T> findAll(Sort sort);
4136

src/main/java/org/springframework/data/couchbase/repository/ReactiveCouchbaseRepository.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
*/
1616
package org.springframework.data.couchbase.repository;
1717

18-
import org.springframework.data.couchbase.core.CouchbaseOperations;
19-
import org.springframework.data.couchbase.core.ReactiveCouchbaseOperations;
2018
import org.springframework.data.repository.NoRepositoryBean;
2119
import org.springframework.data.repository.reactive.ReactiveSortingRepository;
2220

@@ -26,8 +24,5 @@
2624
*/
2725
@NoRepositoryBean
2826
public interface ReactiveCouchbaseRepository<T, ID> extends ReactiveSortingRepository<T, ID> {
29-
/**
30-
* @return a reference to the underlying {@link CouchbaseOperations operation template}.
31-
*/
32-
ReactiveCouchbaseOperations getReactiveCouchbaseOperations();
27+
3328
}

src/main/java/org/springframework/data/couchbase/repository/config/EnableReactiveCouchbaseRepositories.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@
4747

4848
/**
4949
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.:
50-
* {@code @EnableCouchbaseRepositories("org.my.pkg")} instead of
51-
* {@code @EnableCouchbaseRepositories(basePackages="org.my.pkg")}.
50+
* {@code @EnableReactiveCouchbaseRepositories("org.my.pkg")} instead of
51+
* {@code @EnableReactiveCouchbaseRepositories(basePackages="org.my.pkg")}.
5252
*/
5353
String[] value() default {};
5454

@@ -119,6 +119,6 @@
119119
*
120120
* @return
121121
*/
122-
String couchbaseTemplateRef() default BeanNames.COUCHBASE_TEMPLATE;
122+
String couchbaseTemplateRef() default BeanNames.REACTIVE_COUCHBASE_TEMPLATE;
123123

124124
}

src/main/java/org/springframework/data/couchbase/repository/config/ReactiveCouchbaseRepositoryConfigurationExtension.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public void postProcess(BeanDefinitionBuilder builder, XmlRepositoryConfiguratio
109109
public void postProcess(BeanDefinitionBuilder builder, AnnotationRepositoryConfigurationSource config) {
110110

111111
builder.addDependsOn(BeanNames.REACTIVE_COUCHBASE_OPERATIONS_MAPPING);
112-
builder.addPropertyReference("couchbaseOperationsMapping", BeanNames.REACTIVE_COUCHBASE_OPERATIONS_MAPPING);
112+
builder.addPropertyReference("reactiveCouchbaseOperationsMapping", BeanNames.REACTIVE_COUCHBASE_OPERATIONS_MAPPING);
113113
}
114114

115115
/*
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package org.springframework.data.couchbase.repository.query;
2+
3+
import org.springframework.data.couchbase.core.ReactiveCouchbaseOperations;
4+
import org.springframework.data.repository.query.QueryMethod;
5+
import org.springframework.data.repository.query.RepositoryQuery;
6+
7+
public class ReactiveCouchbaseRepositoryQuery implements RepositoryQuery {
8+
9+
private final ReactiveCouchbaseOperations operations;
10+
private final QueryMethod queryMethod;
11+
12+
public ReactiveCouchbaseRepositoryQuery(final ReactiveCouchbaseOperations operations, final QueryMethod queryMethod) {
13+
this.operations = operations;
14+
this.queryMethod = queryMethod;
15+
}
16+
17+
@Override
18+
public Object execute(final Object[] parameters) {
19+
return new ReactiveN1qlRepositoryQueryExecutor(operations, queryMethod).execute(parameters);
20+
}
21+
22+
@Override
23+
public QueryMethod getQueryMethod() {
24+
return queryMethod;
25+
}
26+
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package org.springframework.data.couchbase.repository.query;
2+
3+
import java.util.List;
4+
5+
import org.springframework.data.couchbase.core.CouchbaseOperations;
6+
import org.springframework.data.couchbase.core.ReactiveCouchbaseOperations;
7+
import org.springframework.data.couchbase.core.query.Query;
8+
import org.springframework.data.repository.query.ParameterAccessor;
9+
import org.springframework.data.repository.query.ParametersParameterAccessor;
10+
import org.springframework.data.repository.query.QueryMethod;
11+
import org.springframework.data.repository.query.parser.PartTree;
12+
import reactor.core.publisher.Flux;
13+
14+
public class ReactiveN1qlRepositoryQueryExecutor {
15+
16+
private final ReactiveCouchbaseOperations operations;
17+
private final QueryMethod queryMethod;
18+
19+
public ReactiveN1qlRepositoryQueryExecutor(final ReactiveCouchbaseOperations operations, final QueryMethod queryMethod) {
20+
this.operations = operations;
21+
this.queryMethod = queryMethod;
22+
}
23+
24+
public Object execute(final Object[] parameters) {
25+
final Class<?> domainClass = queryMethod.getResultProcessor().getReturnedType().getDomainType();
26+
final ParameterAccessor accessor = new ParametersParameterAccessor(queryMethod.getParameters(), parameters);
27+
28+
final PartTree tree = new PartTree(queryMethod.getName(), domainClass);
29+
Query query = new N1qlQueryCreator(tree, accessor, operations.getConverter().getMappingContext()).createQuery();
30+
31+
Flux<?> all = operations.findByQuery(domainClass).matching(query).all();
32+
return all;
33+
}
34+
35+
}

src/main/java/org/springframework/data/couchbase/repository/support/ReactiveCouchbaseRepositoryFactory.java

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,15 @@
1919
import java.lang.reflect.Method;
2020
import java.util.Optional;
2121

22+
import org.springframework.data.couchbase.core.CouchbaseOperations;
2223
import org.springframework.data.couchbase.core.ReactiveCouchbaseOperations;
2324
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
2425
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
2526
import org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping;
2627
import org.springframework.data.couchbase.repository.query.CouchbaseEntityInformation;
2728
import org.springframework.data.couchbase.repository.query.CouchbaseQueryMethod;
29+
import org.springframework.data.couchbase.repository.query.CouchbaseRepositoryQuery;
30+
import org.springframework.data.couchbase.repository.query.ReactiveCouchbaseRepositoryQuery;
2831
import org.springframework.data.couchbase.repository.query.ReactivePartTreeN1qlBasedQuery;
2932
import org.springframework.data.couchbase.repository.query.ReactiveStringN1qlBasedQuery;
3033
import org.springframework.data.mapping.context.MappingContext;
@@ -34,6 +37,7 @@
3437
import org.springframework.data.repository.core.RepositoryMetadata;
3538
import org.springframework.data.repository.core.support.ReactiveRepositoryFactorySupport;
3639
import org.springframework.data.repository.query.QueryLookupStrategy;
40+
import org.springframework.data.repository.query.QueryMethod;
3741
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
3842
import org.springframework.data.repository.query.RepositoryQuery;
3943
import org.springframework.expression.spel.standard.SpelExpressionParser;
@@ -57,6 +61,8 @@ public class ReactiveCouchbaseRepositoryFactory extends ReactiveRepositoryFactor
5761
*/
5862
private final MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext;
5963

64+
private final CrudMethodMetadataPostProcessor crudMethodMetadataPostProcessor;
65+
6066
/**
6167
* Create a new factory.
6268
*
@@ -66,8 +72,16 @@ public ReactiveCouchbaseRepositoryFactory(final ReactiveRepositoryOperationsMapp
6672
Assert.notNull(couchbaseOperationsMapping);
6773

6874
this.couchbaseOperationsMapping = couchbaseOperationsMapping;
75+
this.crudMethodMetadataPostProcessor = new CrudMethodMetadataPostProcessor();
6976
mappingContext = this.couchbaseOperationsMapping.getMappingContext();
7077

78+
addRepositoryProxyPostProcessor(crudMethodMetadataPostProcessor);
79+
}
80+
81+
@Override
82+
public void setBeanClassLoader(ClassLoader classLoader) {
83+
super.setBeanClassLoader(classLoader);
84+
this.crudMethodMetadataPostProcessor.setBeanClassLoader(classLoader);
7185
}
7286

7387
/**
@@ -80,9 +94,9 @@ public ReactiveCouchbaseRepositoryFactory(final ReactiveRepositoryOperationsMapp
8094
*/
8195
@Override
8296
public <T, ID> CouchbaseEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
83-
CouchbasePersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(domainClass);
84-
85-
return new MappingCouchbaseEntityInformation<>((CouchbasePersistentEntity<T>) entity);
97+
CouchbasePersistentEntity<T> entity = (CouchbasePersistentEntity<T>) mappingContext
98+
.getRequiredPersistentEntity(domainClass);
99+
return new MappingCouchbaseEntityInformation<>(entity);
86100
}
87101

88102
/**
@@ -97,15 +111,12 @@ public <T, ID> CouchbaseEntityInformation<T, ID> getEntityInformation(Class<T> d
97111
@Override
98112
protected final Object getTargetRepository(final RepositoryInformation metadata) {
99113
ReactiveCouchbaseOperations couchbaseOperations = couchbaseOperationsMapping.resolve(metadata.getRepositoryInterface(),
100-
metadata.getDomainType());
101-
// boolean isN1qlAvailable =
102-
// couchbaseOperations.getCouchbaseClusterConfig().clusterCapabilities().containsKey(ServiceType.QUERY);
103-
114+
metadata.getDomainType());
104115
CouchbaseEntityInformation<?, Serializable> entityInformation = getEntityInformation(metadata.getDomainType());
105-
SimpleReactiveCouchbaseRepository repo = getTargetRepositoryViaReflection(metadata, entityInformation,
106-
couchbaseOperations);
107-
// repo.setViewMetadataProvider(viewPostProcessor.getViewMetadataProvider());
108-
return repo;
116+
SimpleReactiveCouchbaseRepository repository = getTargetRepositoryViaReflection(metadata, entityInformation,
117+
couchbaseOperations);
118+
repository.setRepositoryMethodMetadata(crudMethodMetadataPostProcessor.getCrudMethodMetadata());
119+
return repository;
109120
}
110121

111122
/**
@@ -119,8 +130,6 @@ protected final Object getTargetRepository(final RepositoryInformation metadata)
119130
*/
120131
@Override
121132
protected final Class<?> getRepositoryBaseClass(final RepositoryMetadata repositoryMetadata) {
122-
// Since we always need n1ql (we eliminated use of views for findAll, etc...), lets just
123-
// always return the n1ql repo
124133
return SimpleReactiveCouchbaseRepository.class;
125134
}
126135

@@ -144,23 +153,10 @@ public CouchbaseQueryLookupStrategy(QueryMethodEvaluationContextProvider evaluat
144153
@Override
145154
public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
146155
NamedQueries namedQueries) {
147-
ReactiveCouchbaseOperations couchbaseOperations = couchbaseOperationsMapping.resolve(metadata.getRepositoryInterface(),
148-
metadata.getDomainType());
149-
150-
CouchbaseQueryMethod queryMethod = new CouchbaseQueryMethod(method, metadata, factory, mappingContext);
151-
String namedQueryName = queryMethod.getNamedQueryName();
152-
153-
if (queryMethod.hasN1qlAnnotation()) {
154-
if (queryMethod.hasInlineN1qlQuery()) {
155-
return new ReactiveStringN1qlBasedQuery(queryMethod.getInlineN1qlQuery(), queryMethod, couchbaseOperations,
156-
SPEL_PARSER, evaluationContextProvider);
157-
} else if (namedQueries.hasQuery(namedQueryName)) {
158-
String namedQuery = namedQueries.getQuery(namedQueryName);
159-
return new ReactiveStringN1qlBasedQuery(namedQuery, queryMethod, couchbaseOperations, SPEL_PARSER,
160-
evaluationContextProvider);
161-
} // otherwise will do default, queryDerivation
162-
}
163-
return new ReactivePartTreeN1qlBasedQuery(queryMethod, couchbaseOperations);
156+
final ReactiveCouchbaseOperations couchbaseOperations = couchbaseOperationsMapping
157+
.resolve(metadata.getRepositoryInterface(), metadata.getDomainType());
158+
159+
return new ReactiveCouchbaseRepositoryQuery(couchbaseOperations, new QueryMethod(method, metadata, factory));
164160
}
165161
}
166162

src/main/java/org/springframework/data/couchbase/repository/support/ReactiveCouchbaseRepositoryFactoryBean.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ public ReactiveCouchbaseRepositoryFactoryBean(Class<? extends T> repositoryInter
5151
* @param reactiveCouchbaseOperations the reference to the operations template.
5252
*/
5353
public void setCouchbaseOperations(final ReactiveCouchbaseOperations reactiveCouchbaseOperations) {
54-
setCouchbaseOperationsMapping(new ReactiveRepositoryOperationsMapping(reactiveCouchbaseOperations));
54+
setReactiveCouchbaseOperationsMapping(new ReactiveRepositoryOperationsMapping(reactiveCouchbaseOperations));
5555
}
5656

57-
public void setCouchbaseOperationsMapping(final ReactiveRepositoryOperationsMapping couchbaseOperationsMapping) {
57+
public void setReactiveCouchbaseOperationsMapping(final ReactiveRepositoryOperationsMapping couchbaseOperationsMapping) {
5858
this.couchbaseOperationsMapping = couchbaseOperationsMapping;
5959
setMappingContext(couchbaseOperationsMapping.getMappingContext());
6060
}

src/main/java/org/springframework/data/couchbase/repository/support/SimpleCouchbaseRepository.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,6 @@ public Page<T> findAll(final Pageable pageable) {
153153
return new PageImpl<>(results, pageable, count());
154154
}
155155

156-
@Override
157-
public CouchbaseOperations getCouchbaseOperations() {
158-
return couchbaseOperations;
159-
}
160-
161156
/**
162157
* Returns the information for the underlying template.
163158
*

src/main/java/org/springframework/data/couchbase/repository/support/SimpleReactiveCouchbaseRepository.java

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.data.couchbase.repository.support;
1818

19+
import com.couchbase.client.java.query.QueryScanConsistency;
1920
import reactor.core.publisher.Flux;
2021
import reactor.core.publisher.Mono;
2122

@@ -55,18 +56,20 @@ public class SimpleReactiveCouchbaseRepository<T, ID> implements ReactiveCouchba
5556
*/
5657
private final CouchbaseEntityInformation<T, String> entityInformation;
5758

59+
private CrudMethodMetadata crudMethodMetadata;
60+
5861
/**
5962
* Create a new Repository.
6063
*
61-
* @param metadata the Metadata for the entity.
64+
* @param entityInformation the Metadata for the entity.
6265
* @param operations the reference to the reactive template used.
6366
*/
64-
public SimpleReactiveCouchbaseRepository(final CouchbaseEntityInformation<T, String> metadata,
67+
public SimpleReactiveCouchbaseRepository(final CouchbaseEntityInformation<T, String> entityInformation,
6568
final ReactiveCouchbaseOperations operations) {
66-
Assert.notNull(operations, "RxJavaCouchbaseOperations must not be null!");
67-
Assert.notNull(metadata, "CouchbaseEntityInformation must not be null!");
69+
Assert.notNull(operations, "ReactiveCouchbaseOperations must not be null!");
70+
Assert.notNull(entityInformation, "CouchbaseEntityInformation must not be null!");
6871

69-
this.entityInformation = metadata;
72+
this.entityInformation = entityInformation;
7073
this.operations = operations;
7174
}
7275

@@ -195,13 +198,25 @@ protected CouchbaseEntityInformation<T, String> getEntityInformation() {
195198
return entityInformation;
196199
}
197200

198-
@Override
199-
public ReactiveCouchbaseOperations getReactiveCouchbaseOperations() {
200-
return operations;
201+
private Flux<T> findAll(final Query query) {
202+
return operations.findByQuery(entityInformation.getJavaType()).consistentWith(buildQueryScanConsistency()).matching(query).all();
201203
}
202204

203-
private Flux<T> findAll(final Query query) {
204-
return operations.findByQuery(entityInformation.getJavaType()).matching(query).all();
205+
private QueryScanConsistency buildQueryScanConsistency() {
206+
QueryScanConsistency scanConsistency = QueryScanConsistency.NOT_BOUNDED;
207+
if (crudMethodMetadata.getScanConsistency() != null) {
208+
scanConsistency = crudMethodMetadata.getScanConsistency().query();
209+
}
210+
return scanConsistency;
211+
}
212+
213+
/**
214+
* Setter for the repository metadata, contains annotations on the overidden methods.
215+
*
216+
* @param crudMethodMetadata the injected repository metadata.
217+
*/
218+
void setRepositoryMethodMetadata(final CrudMethodMetadata crudMethodMetadata) {
219+
this.crudMethodMetadata = crudMethodMetadata;
205220
}
206221

207222
}

src/test/java/org/springframework/data/couchbase/core/CouchbaseTemplateKeyValueIntegrationTests.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static org.junit.jupiter.api.Assertions.*;
2020

2121
import java.io.IOException;
22+
import java.time.Duration;
2223
import java.util.UUID;
2324

2425
import org.junit.jupiter.api.AfterAll;
@@ -44,6 +45,7 @@ class CouchbaseTemplateKeyValueIntegrationTests extends ClusterAwareIntegrationT
4445
@BeforeAll
4546
static void beforeAll() {
4647
couchbaseClientFactory = new SimpleCouchbaseClientFactory(connectionString(), authenticator(), bucketName());
48+
couchbaseClientFactory.getBucket().waitUntilReady(Duration.ofSeconds(10));
4749
}
4850

4951
@AfterAll

0 commit comments

Comments
 (0)