From 54ff297a8c9fbdf41121cc1b1125d80a1cfe9bb1 Mon Sep 17 00:00:00 2001 From: Michael Reiche <48999328+mikereiche@users.noreply.github.com> Date: Wed, 16 Dec 2020 14:23:24 -0800 Subject: [PATCH] DATACOUCH-550 - Autoindexing does not work spring-boot application. Due to the interdependencies of beans, autoindexing does not work in the startup of a normal spring-boot application. Processing of entities occurs during the initialization of CouchbaseMappinContext, which occurs before initialization of MappingCouchbaseConverter, which occurs before the initialization of CouchbaseTemplate - which creates the indexCreator listener. So when the AbstractMappingContext (CouchbaseMappingContext) is publishing MappingContextEvents - there is not yet any indexCreator. And subsequent processing of entities finds the entities cached, and therefore does not publish MappingContextEvents. This change overrides the addPersistentEntity() and getPersistentEntity() methods of AbstractMappingContext such that caching does not preven the MappingContextEvents from being published. This change also exposes indexCreator classesSeen map to CouchbaseMappingContext so that once an entity has been processed by indexCreator, it is not published again. Autoindexing by SpringJUnitConfig did work prior to this change. Co-authored-by: mikereiche --- .../couchbase/core/CouchbaseTemplate.java | 4 ++ ...CouchbasePersistentEntityIndexCreator.java | 3 + .../core/mapping/CouchbaseMappingContext.java | 58 +++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java b/src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java index 4458d98a1..2648a8e7e 100644 --- a/src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java +++ b/src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java @@ -166,6 +166,10 @@ private void prepareIndexCreator(final ApplicationContext context) { if (context instanceof ConfigurableApplicationContext && indexCreator != null) { ((ConfigurableApplicationContext) context).addApplicationListener(indexCreator); + if (mappingContext instanceof CouchbaseMappingContext) { + CouchbaseMappingContext cmc = (CouchbaseMappingContext) mappingContext; + cmc.setIndexCreator(indexCreator); + } } } } diff --git a/src/main/java/org/springframework/data/couchbase/core/index/CouchbasePersistentEntityIndexCreator.java b/src/main/java/org/springframework/data/couchbase/core/index/CouchbasePersistentEntityIndexCreator.java index 17d2753cc..39ca60b7f 100644 --- a/src/main/java/org/springframework/data/couchbase/core/index/CouchbasePersistentEntityIndexCreator.java +++ b/src/main/java/org/springframework/data/couchbase/core/index/CouchbasePersistentEntityIndexCreator.java @@ -121,4 +121,7 @@ public boolean isIndexCreatorFor(final MappingContext context) { return this.mappingContext.equals(context); } + public boolean hasSeen(CouchbasePersistentEntity entity) { + return classesSeen.containsKey(entity.getType()); + } } diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseMappingContext.java b/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseMappingContext.java index 1becd978f..6421dcd60 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseMappingContext.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseMappingContext.java @@ -16,10 +16,15 @@ package org.springframework.data.couchbase.core.mapping; +import java.util.Optional; + import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.data.couchbase.core.index.CouchbasePersistentEntityIndexCreator; import org.springframework.data.mapping.context.AbstractMappingContext; +import org.springframework.data.mapping.context.MappingContextEvent; import org.springframework.data.mapping.model.FieldNamingStrategy; import org.springframework.data.mapping.model.Property; import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy; @@ -31,6 +36,7 @@ * {@link BasicCouchbasePersistentEntity} and {@link BasicCouchbasePersistentProperty} as primary abstractions. * * @author Michael Nitschinger + * @author Michael Reiche */ public class CouchbaseMappingContext extends AbstractMappingContext, CouchbasePersistentProperty> @@ -50,6 +56,8 @@ public class CouchbaseMappingContext private FieldNamingStrategy fieldNamingStrategy = DEFAULT_NAMING_STRATEGY; private boolean autoIndexCreation = true; + private ApplicationEventPublisher eventPublisher; + private CouchbasePersistentEntityIndexCreator indexCreator = null; /** * Configures the {@link FieldNamingStrategy} to be used to determine the field name if no manual mapping is applied. @@ -101,6 +109,15 @@ protected CouchbasePersistentProperty createPersistentProperty(Property property @Override public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException { context = applicationContext; + super.setApplicationContext(applicationContext); + } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + eventPublisher = applicationEventPublisher; + if (this.eventPublisher == null) { + this.eventPublisher = context; + } } public boolean isAutoIndexCreation() { @@ -111,4 +128,45 @@ public void setAutoIndexCreation(boolean autoCreateIndexes) { this.autoIndexCreation = autoCreateIndexes; } + /** + * override method from AbstractMappingContext as that method will not publishEvent() if it finds the entity has + * already been cached + * + * @param typeInformation - entity type + */ + @Override + protected Optional> addPersistentEntity(TypeInformation typeInformation) { + Optional> entity = super.addPersistentEntity(typeInformation); + + if (this.eventPublisher != null && entity.isPresent()) { + if (this.indexCreator != null) { + if (!indexCreator.hasSeen(entity.get())) { + this.eventPublisher.publishEvent(new MappingContextEvent(this, entity.get())); + } + } + } + return entity; + } + + /** + * override method from AbstractMappingContext as that method will not publishEvent() if it finds the entity has + * already been cached. Instead, user our own addPersistEntity that will. + * + * @param typeInformation - entity type + */ + @Override + public BasicCouchbasePersistentEntity getPersistentEntity(TypeInformation typeInformation) { + Optional> entity = addPersistentEntity(typeInformation); + return entity.isPresent() ? entity.get() : null; + } + + /** + * capture the indexCreator when it has been added as a listener. only publishEvent() if the indexCreator hasn't + * already seen the class. + * + * @param indexCreator + */ + public void setIndexCreator(CouchbasePersistentEntityIndexCreator indexCreator) { + this.indexCreator = indexCreator; + } }