Skip to content

Commit e281daa

Browse files
Refactored the usage of CouchbasePersistentEntityIndexCreator
pom.xml - updated CouchbaseMock dependency to the official release on maven central, which now includes the required commit. CouchbaseTemplate.java - remove creation of CouchbasePersistentEntityIndexCreator - there can only be a single CouchbaseMappingContext and CouchbasePersistentEntityIndexCreator, not sure why there was code dealing with multiples of each, and there was no corresponding tests for these assumptions. - no longer does the job of a @Configuation class by gluing beans together with their dependencies. CouchbaseMappingContext.java - removed references to auto index creation, that functionality should be a completely separate concern. CouchbasePersistentEntityIndexCreator.java - no longer implements ApplicationListener - but instead calls CouchbaseMappingContext#getPersistentEntities to retrieve the list of entity candidates for index creation. - now implements InitializingBean, to trigger the creation of any needed indices. - added a boolean flag to indicate if automatic index creation is to be enabled or now, passed in by the factory method that creates this bean. - minor logging cleanup, use property placeholders where appropriate AbstractCouchbaseConfiguration.java - added a new factory method for the CouchbasePersistentEntityIndexCreator bean. - CouchbaseMappingContext no longer has anything to do with index creation, other than supplying a candidate list of entities that may need indices. Prompted by: spring-projects/spring-boot#24525 and the discussion on #295
1 parent 9c9dde7 commit e281daa

File tree

5 files changed

+37
-137
lines changed

5 files changed

+37
-137
lines changed

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,9 @@
150150
</dependency>
151151

152152
<dependency>
153-
<groupId>com.github.Couchbase</groupId>
153+
<groupId>com.couchbase.mock</groupId>
154154
<artifactId>CouchbaseMock</artifactId>
155-
<version>73e493d259</version>
155+
<version>1.5.25</version>
156156
<scope>test</scope>
157157
</dependency>
158158

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,14 @@
3131
import org.springframework.data.convert.CustomConversions;
3232
import org.springframework.data.couchbase.CouchbaseClientFactory;
3333
import org.springframework.data.couchbase.SimpleCouchbaseClientFactory;
34+
import org.springframework.data.couchbase.core.CouchbaseOperations;
3435
import org.springframework.data.couchbase.core.CouchbaseTemplate;
3536
import org.springframework.data.couchbase.core.ReactiveCouchbaseTemplate;
3637
import org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions;
3738
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
3839
import org.springframework.data.couchbase.core.convert.translation.JacksonTranslationService;
3940
import org.springframework.data.couchbase.core.convert.translation.TranslationService;
41+
import org.springframework.data.couchbase.core.index.CouchbasePersistentEntityIndexCreator;
4042
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
4143
import org.springframework.data.couchbase.core.mapping.Document;
4244
import org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping;
@@ -268,7 +270,6 @@ public CouchbaseMappingContext couchbaseMappingContext(CustomConversions customC
268270
mappingContext.setInitialEntitySet(getInitialEntitySet());
269271
mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
270272
mappingContext.setFieldNamingStrategy(fieldNamingStrategy());
271-
mappingContext.setAutoIndexCreation(autoIndexCreation());
272273

273274
return mappingContext;
274275
}
@@ -280,6 +281,18 @@ protected boolean autoIndexCreation() {
280281
return false;
281282
}
282283

284+
/**
285+
* Creates a {@link CouchbasePersistentEntityIndexCreator} bean that takes on the responsibility of automatically
286+
* creating indices.
287+
*
288+
* Does nothing if {@link #autoIndexCreation()} returns false.
289+
*/
290+
@Bean
291+
public CouchbasePersistentEntityIndexCreator couchbasePersistentEntityIndexCreator(CouchbaseMappingContext couchbaseMappingContext,
292+
CouchbaseOperations couchbaseOperations) {
293+
return new CouchbasePersistentEntityIndexCreator(couchbaseMappingContext, couchbaseOperations, autoIndexCreation());
294+
}
295+
283296
/**
284297
* Register custom Converters in a {@link CustomConversions} object if required. These {@link CustomConversions} will
285298
* be registered with the {@link #mappingCouchbaseConverter(CouchbaseMappingContext, CouchbaseCustomConversions)} )}

src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,8 @@
1919
import org.springframework.beans.BeansException;
2020
import org.springframework.context.ApplicationContext;
2121
import org.springframework.context.ApplicationContextAware;
22-
import org.springframework.context.ConfigurableApplicationContext;
2322
import org.springframework.data.couchbase.CouchbaseClientFactory;
2423
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
25-
import org.springframework.data.couchbase.core.index.CouchbasePersistentEntityIndexCreator;
26-
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
27-
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
28-
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
29-
import org.springframework.data.mapping.context.MappingContext;
30-
import org.springframework.lang.Nullable;
3124

3225
import com.couchbase.client.java.Collection;
3326

@@ -36,30 +29,21 @@
3629
*
3730
* @author Michael Nitschinger
3831
* @author Michael Reiche
32+
* @author Aaron Whiteside
3933
* @since 3.0
4034
*/
4135
public class CouchbaseTemplate implements CouchbaseOperations, ApplicationContextAware {
4236

4337
private final CouchbaseClientFactory clientFactory;
4438
private final CouchbaseConverter converter;
4539
private final CouchbaseTemplateSupport templateSupport;
46-
private final MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext;
4740
private final ReactiveCouchbaseTemplate reactiveCouchbaseTemplate;
48-
private @Nullable CouchbasePersistentEntityIndexCreator indexCreator;
4941

5042
public CouchbaseTemplate(final CouchbaseClientFactory clientFactory, final CouchbaseConverter converter) {
5143
this.clientFactory = clientFactory;
5244
this.converter = converter;
5345
this.templateSupport = new CouchbaseTemplateSupport(converter);
5446
this.reactiveCouchbaseTemplate = new ReactiveCouchbaseTemplate(clientFactory, converter);
55-
56-
this.mappingContext = this.converter.getMappingContext();
57-
if (mappingContext instanceof CouchbaseMappingContext) {
58-
CouchbaseMappingContext cmc = (CouchbaseMappingContext) mappingContext;
59-
if (cmc.isAutoIndexCreation()) {
60-
indexCreator = new CouchbasePersistentEntityIndexCreator(cmc, this);
61-
}
62-
}
6347
}
6448

6549
@Override
@@ -148,28 +132,7 @@ public ReactiveCouchbaseTemplate reactive() {
148132

149133
@Override
150134
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
151-
prepareIndexCreator(applicationContext);
152135
templateSupport.setApplicationContext(applicationContext);
153136
reactiveCouchbaseTemplate.setApplicationContext(applicationContext);
154137
}
155-
156-
private void prepareIndexCreator(final ApplicationContext context) {
157-
String[] indexCreators = context.getBeanNamesForType(CouchbasePersistentEntityIndexCreator.class);
158-
159-
for (String creator : indexCreators) {
160-
CouchbasePersistentEntityIndexCreator creatorBean = context.getBean(creator,
161-
CouchbasePersistentEntityIndexCreator.class);
162-
if (creatorBean.isIndexCreatorFor(mappingContext)) {
163-
return;
164-
}
165-
}
166-
167-
if (context instanceof ConfigurableApplicationContext && indexCreator != null) {
168-
((ConfigurableApplicationContext) context).addApplicationListener(indexCreator);
169-
if (mappingContext instanceof CouchbaseMappingContext) {
170-
CouchbaseMappingContext cmc = (CouchbaseMappingContext) mappingContext;
171-
cmc.setIndexCreator(indexCreator);
172-
}
173-
}
174-
}
175138
}

src/main/java/org/springframework/data/couchbase/core/index/CouchbasePersistentEntityIndexCreator.java

Lines changed: 18 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,47 +20,47 @@
2020

2121
import org.slf4j.Logger;
2222
import org.slf4j.LoggerFactory;
23-
import org.springframework.context.ApplicationListener;
23+
import org.springframework.beans.factory.InitializingBean;
2424
import org.springframework.dao.DataIntegrityViolationException;
2525
import org.springframework.data.couchbase.core.CouchbaseOperations;
2626
import org.springframework.data.couchbase.core.index.CouchbasePersistentEntityIndexResolver.IndexDefinitionHolder;
2727
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
2828
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
2929
import org.springframework.data.couchbase.core.mapping.Document;
30-
import org.springframework.data.mapping.PersistentEntity;
31-
import org.springframework.data.mapping.context.MappingContext;
32-
import org.springframework.data.mapping.context.MappingContextEvent;
3330

3431
import com.couchbase.client.core.error.IndexExistsException;
3532
import com.couchbase.client.java.Cluster;
3633

37-
public class CouchbasePersistentEntityIndexCreator implements ApplicationListener<MappingContextEvent<?, ?>> {
34+
/**
35+
* Encapsulates the logic of creating indices.
36+
*
37+
* @author Michael Nitschinger
38+
* @author Aaron Whiteside
39+
*/
40+
public class CouchbasePersistentEntityIndexCreator implements InitializingBean {
3841

3942
private static final Logger LOGGER = LoggerFactory.getLogger(CouchbasePersistentEntityIndexCreator.class);
4043

4144
private final Map<Class<?>, Boolean> classesSeen = new ConcurrentHashMap<>();
4245
private final CouchbaseMappingContext mappingContext;
4346
private final QueryIndexResolver indexResolver;
4447
private final CouchbaseOperations couchbaseOperations;
48+
private final boolean enabled;
4549

4650
public CouchbasePersistentEntityIndexCreator(final CouchbaseMappingContext mappingContext,
47-
final CouchbaseOperations operations) {
51+
final CouchbaseOperations operations, final boolean enabled) {
4852
this.mappingContext = mappingContext;
4953
this.couchbaseOperations = operations;
54+
this.enabled = enabled;
5055
this.indexResolver = QueryIndexResolver.create(mappingContext, operations);
5156
}
5257

5358
@Override
54-
public void onApplicationEvent(final MappingContextEvent<?, ?> event) {
55-
if (!event.wasEmittedBy(mappingContext)) {
56-
return;
57-
}
58-
59-
PersistentEntity<?, ?> entity = event.getPersistentEntity();
60-
61-
// Double check type as Spring infrastructure does not consider nested generics
62-
if (entity instanceof CouchbasePersistentEntity) {
63-
checkForIndexes((CouchbasePersistentEntity<?>) entity);
59+
public void afterPropertiesSet() throws Exception {
60+
if (enabled) {
61+
mappingContext.getPersistentEntities().forEach(this::checkForIndexes);
62+
} else {
63+
LOGGER.debug("Automatic index creation not enabled.");
6464
}
6565
}
6666

@@ -71,7 +71,7 @@ private void checkForIndexes(final CouchbasePersistentEntity<?> entity) {
7171
this.classesSeen.put(type, Boolean.TRUE);
7272

7373
if (LOGGER.isDebugEnabled()) {
74-
LOGGER.debug("Analyzing class " + type + " for index information.");
74+
LOGGER.debug("Analyzing class {} for index information.", type);
7575
}
7676

7777
checkForAndCreateIndexes(entity);
@@ -107,21 +107,10 @@ private void createIndex(final IndexDefinitionHolder indexToCreate) {
107107
cluster.query(statement.toString());
108108
} catch (IndexExistsException ex) {
109109
// ignored on purpose, rest is propagated
110-
LOGGER.debug("Index \"" + indexToCreate.getIndexName() + "\" already exists, ignoring.");
110+
LOGGER.debug("Index \"{}\" already exists, ignoring.", indexToCreate.getIndexName());
111111
} catch (Exception ex) {
112112
throw new DataIntegrityViolationException("Could not auto-create index with statement: " + statement.toString(),
113113
ex);
114114
}
115115
}
116-
117-
/**
118-
* Returns whether the current index creator was registered for the given {@link MappingContext}.
119-
*/
120-
public boolean isIndexCreatorFor(final MappingContext<?, ?> context) {
121-
return this.mappingContext.equals(context);
122-
}
123-
124-
public boolean hasSeen(CouchbasePersistentEntity<?> entity) {
125-
return classesSeen.containsKey(entity.getType());
126-
}
127116
}

src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseMappingContext.java

Lines changed: 2 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,10 @@
1616

1717
package org.springframework.data.couchbase.core.mapping;
1818

19-
import java.util.Optional;
20-
2119
import org.springframework.beans.BeansException;
2220
import org.springframework.context.ApplicationContext;
2321
import org.springframework.context.ApplicationContextAware;
24-
import org.springframework.context.ApplicationEventPublisher;
25-
import org.springframework.data.couchbase.core.index.CouchbasePersistentEntityIndexCreator;
2622
import org.springframework.data.mapping.context.AbstractMappingContext;
27-
import org.springframework.data.mapping.context.MappingContextEvent;
2823
import org.springframework.data.mapping.model.FieldNamingStrategy;
2924
import org.springframework.data.mapping.model.Property;
3025
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
@@ -37,6 +32,7 @@
3732
*
3833
* @author Michael Nitschinger
3934
* @author Michael Reiche
35+
* @author Aaron Whiteside
4036
*/
4137
public class CouchbaseMappingContext
4238
extends AbstractMappingContext<BasicCouchbasePersistentEntity<?>, CouchbasePersistentProperty>
@@ -55,10 +51,6 @@ public class CouchbaseMappingContext
5551
*/
5652
private FieldNamingStrategy fieldNamingStrategy = DEFAULT_NAMING_STRATEGY;
5753

58-
private boolean autoIndexCreation = true;
59-
private ApplicationEventPublisher eventPublisher;
60-
private CouchbasePersistentEntityIndexCreator indexCreator = null;
61-
6254
/**
6355
* Configures the {@link FieldNamingStrategy} to be used to determine the field name if no manual mapping is applied.
6456
* Defaults to a strategy using the plain property name.
@@ -108,65 +100,8 @@ protected CouchbasePersistentProperty createPersistentProperty(Property property
108100
*/
109101
@Override
110102
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
111-
context = applicationContext;
112103
super.setApplicationContext(applicationContext);
104+
context = applicationContext;
113105
}
114106

115-
@Override
116-
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
117-
eventPublisher = applicationEventPublisher;
118-
if (this.eventPublisher == null) {
119-
this.eventPublisher = context;
120-
}
121-
}
122-
123-
public boolean isAutoIndexCreation() {
124-
return autoIndexCreation;
125-
}
126-
127-
public void setAutoIndexCreation(boolean autoCreateIndexes) {
128-
this.autoIndexCreation = autoCreateIndexes;
129-
}
130-
131-
/**
132-
* override method from AbstractMappingContext as that method will not publishEvent() if it finds the entity has
133-
* already been cached
134-
*
135-
* @param typeInformation - entity type
136-
*/
137-
@Override
138-
protected Optional<BasicCouchbasePersistentEntity<?>> addPersistentEntity(TypeInformation<?> typeInformation) {
139-
Optional<BasicCouchbasePersistentEntity<?>> entity = super.addPersistentEntity(typeInformation);
140-
141-
if (this.eventPublisher != null && entity.isPresent()) {
142-
if (this.indexCreator != null) {
143-
if (!indexCreator.hasSeen(entity.get())) {
144-
this.eventPublisher.publishEvent(new MappingContextEvent(this, entity.get()));
145-
}
146-
}
147-
}
148-
return entity;
149-
}
150-
151-
/**
152-
* override method from AbstractMappingContext as that method will not publishEvent() if it finds the entity has
153-
* already been cached. Instead, user our own addPersistEntity that will.
154-
*
155-
* @param typeInformation - entity type
156-
*/
157-
@Override
158-
public BasicCouchbasePersistentEntity<?> getPersistentEntity(TypeInformation<?> typeInformation) {
159-
Optional<BasicCouchbasePersistentEntity<?>> entity = addPersistentEntity(typeInformation);
160-
return entity.isPresent() ? entity.get() : null;
161-
}
162-
163-
/**
164-
* capture the indexCreator when it has been added as a listener. only publishEvent() if the indexCreator hasn't
165-
* already seen the class.
166-
*
167-
* @param indexCreator
168-
*/
169-
public void setIndexCreator(CouchbasePersistentEntityIndexCreator indexCreator) {
170-
this.indexCreator = indexCreator;
171-
}
172107
}

0 commit comments

Comments
 (0)