From 3f968526b77b3ea8e011c7266dfa4079463d4733 Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Thu, 14 Jan 2021 19:18:20 +0100 Subject: [PATCH] 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. --- ...gmEntityInstantiatorConfigurationBean.java | 27 ++++++++++++--- ...Neo4jRepositoryConfigurationExtension.java | 34 +++++++++++++------ 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jOgmEntityInstantiatorConfigurationBean.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jOgmEntityInstantiatorConfigurationBean.java index 6f4469080..96cf14333 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jOgmEntityInstantiatorConfigurationBean.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jOgmEntityInstantiatorConfigurationBean.java @@ -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 conversionServiceObjectProvider) { + private final SessionFactory sessionFactory; + private final Neo4jMappingContext mappingContext; + private final ObjectProvider conversionServiceObjectProvider; + public Neo4jOgmEntityInstantiatorConfigurationBean( + SessionFactory sessionFactory, Neo4jMappingContext mappingContext, + ObjectProvider 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)); diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jRepositoryConfigurationExtension.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jRepositoryConfigurationExtension.java index 02a7650f2..68b8b909d 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jRepositoryConfigurationExtension.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jRepositoryConfigurationExtension.java @@ -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