DATACOUCH-550 - Autoindexing does not work spring-boot application. (#297)

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 <michael.reiche@couchbase.com>

Co-authored-by: mikereiche <michael.reiche@couchbase.com>
This commit is contained in:
Michael Reiche
2020-12-16 15:02:46 -08:00
committed by GitHub
parent 6c6dc13de4
commit 03ad3697ae
3 changed files with 65 additions and 0 deletions

View File

@@ -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);
}
}
}
}

View File

@@ -121,4 +121,7 @@ public class CouchbasePersistentEntityIndexCreator implements ApplicationListene
return this.mappingContext.equals(context);
}
public boolean hasSeen(CouchbasePersistentEntity<?> entity) {
return classesSeen.containsKey(entity.getType());
}
}

View File

@@ -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<BasicCouchbasePersistentEntity<?>, 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<BasicCouchbasePersistentEntity<?>> addPersistentEntity(TypeInformation<?> typeInformation) {
Optional<BasicCouchbasePersistentEntity<?>> 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<BasicCouchbasePersistentEntity<?>> 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;
}
}