From 8ebb81b62dc25161dd40d6bbec3462ebae78397a 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 autoindex not working in spring boot app (#295) * DATACOUCH-550 Autoindexing only works from SpringJunitConfig Due to the interdependency in bean creation, Autoindexing does not work in a normal spring-boot application. This change overrides the addPersistentEntity and getPersistentEntity of CouchbaseMappingContext to avoid entries cached before the indexCreator was listening from preventing MappingContextEvents from being published after the indexCreator is listening. It also exposes the indexCreators classesSeen map so that MappingEvents for an entity are not re-published after the indexCreator has seen them. * 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 4458d98a..2648a8e7 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 @@ public class CouchbaseTemplate implements CouchbaseOperations, ApplicationContex 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 17d2753c..39ca60b7 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 class CouchbasePersistentEntityIndexCreator implements ApplicationListene 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 1becd978..6421dcd6 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 @@ import org.springframework.data.util.TypeInformation; * {@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 @@ public class CouchbaseMappingContext @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 class CouchbaseMappingContext 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; + } }