GH-2099 - Declare the dependency between shared session creator and entity instantiator.

The conversion service is picked up to late as the the dependency
between the shared session creator and the bean that does the post
processing of the underlying session factory is undefined for the Spring
context.

By explicit stating this in the repository extension, the
`Neo4jOgmEntityInstantiatorConfigurationBean` is correctly initialized
upfront without messing around with an actual post processor or
orderings.

This closes #2099.
This commit is contained in:
Michael Simons
2021-01-14 19:18:20 +01:00
parent 2dd7b06b2c
commit 3f968526b7
2 changed files with 46 additions and 15 deletions

View File

@@ -15,25 +15,44 @@
*/
package org.springframework.data.neo4j.repository.config;
import javax.annotation.PostConstruct;
import org.neo4j.ogm.metadata.MetaData;
import org.neo4j.ogm.session.SessionFactory;
import org.neo4j.ogm.typeconversion.ConversionCallback;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.neo4j.conversion.MetaDataDrivenConversionService;
import org.springframework.data.neo4j.conversion.Neo4jOgmEntityInstantiatorAdapter;
import org.springframework.data.neo4j.mapping.Neo4jMappingContext;
/**
*
* @author Gerrit Meier
* @author Michael J. Simons
*/
class Neo4jOgmEntityInstantiatorConfigurationBean {
class Neo4jOgmEntityInstantiatorConfigurationBean implements InitializingBean {
public Neo4jOgmEntityInstantiatorConfigurationBean(SessionFactory sessionFactory, Neo4jMappingContext mappingContext,
ObjectProvider<ConversionService> conversionServiceObjectProvider) {
private final SessionFactory sessionFactory;
private final Neo4jMappingContext mappingContext;
private final ObjectProvider<ConversionService> conversionServiceObjectProvider;
public Neo4jOgmEntityInstantiatorConfigurationBean(
SessionFactory sessionFactory, Neo4jMappingContext mappingContext,
ObjectProvider<ConversionService> conversionServiceObjectProvider
) {
this.sessionFactory = sessionFactory;
this.mappingContext = mappingContext;
this.conversionServiceObjectProvider = conversionServiceObjectProvider;
}
@Override
public void afterPropertiesSet() {
MetaData metaData = sessionFactory.metaData();
ConversionService conversionService = conversionServiceObjectProvider
.getIfUnique(() -> new MetaDataDrivenConversionService(metaData));

View File

@@ -23,6 +23,8 @@ import java.util.Optional;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.RelationshipEntity;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
@@ -189,23 +191,29 @@ public class Neo4jRepositoryConfigurationExtension extends RepositoryConfigurati
return;
}
String configuredSessionBeanName = config.getAttribute("sessionBeanName").orElse(GENERATE_BEAN_NAME);
this.sessionBeanName = registerWithGeneratedNameOrUseConfigured(createSharedSessionCreatorBeanDefinition(config),
registry, configuredSessionBeanName, source);
String configuredMappingContextBeanName = config.getAttribute("mappingContextBeanName").orElse(GENERATE_BEAN_NAME);
String configuredSessionBeanName = config.getAttribute("sessionBeanName").orElse(GENERATE_BEAN_NAME);
// Register mapping context
this.neo4jMappingContextBeanName = registerWithGeneratedNameOrUseConfigured(
createNeo4jMappingContextFactoryBeanDefinition(config), registry, configuredMappingContextBeanName, source);
registerIfNotAlreadyRegistered(() -> new RootBeanDefinition(Neo4jPersistenceExceptionTranslator.class), registry,
NEO4J_PERSISTENCE_EXCEPTION_TRANSLATOR_NAME, source);
// Prepare session factory postprocessor
AbstractBeanDefinition rootBeanDefinition = BeanDefinitionBuilder
.rootBeanDefinition(Neo4jOgmEntityInstantiatorConfigurationBean.class)
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR)
.addConstructorArgReference(getSessionFactoryBeanName(config))
.addConstructorArgReference(this.neo4jMappingContextBeanName).getBeanDefinition();
registerWithGeneratedNameOrUseConfigured(rootBeanDefinition, registry, GENERATE_BEAN_NAME, source);
.addConstructorArgReference(this.neo4jMappingContextBeanName)
.getBeanDefinition();
String sessionFactoryPostProcessorBeanName = registerWithGeneratedNameOrUseConfigured(
rootBeanDefinition, registry, GENERATE_BEAN_NAME, source);
// Make sure the shared session creator depends on it
this.sessionBeanName = registerWithGeneratedNameOrUseConfigured(
createSharedSessionCreatorBeanDefinition(config, sessionFactoryPostProcessorBeanName), registry, configuredSessionBeanName, source);
registerIfNotAlreadyRegistered(() -> new RootBeanDefinition(Neo4jPersistenceExceptionTranslator.class), registry,
NEO4J_PERSISTENCE_EXCEPTION_TRANSLATOR_NAME, source);
}
/**
@@ -236,13 +244,17 @@ public class Neo4jRepositoryConfigurationExtension extends RepositoryConfigurati
return registeredBeanName;
}
private static AbstractBeanDefinition createSharedSessionCreatorBeanDefinition(RepositoryConfigurationSource config) {
private static AbstractBeanDefinition createSharedSessionCreatorBeanDefinition(
RepositoryConfigurationSource config,
String sessionFactoryPostProcessorBeanName
) {
String sessionFactoryBeanName = getSessionFactoryBeanName(config);
AbstractBeanDefinition sharedSessionCreatorBeanDefinition = BeanDefinitionBuilder //
.rootBeanDefinition(SharedSessionCreator.class, "createSharedSession") //
.addConstructorArgReference(sessionFactoryBeanName) //
.addDependsOn(sessionFactoryPostProcessorBeanName)
.getBeanDefinition();
sharedSessionCreatorBeanDefinition