Include vendor properties in auto-configured EntityManagerFactoryBuilder
This commit moves the setup of vendor properties (e.g. Hibernate) from the auto-configured LocalContainerEntityManagerFactoryBean to the auto-configured EntityManagerFactoryBuilder. This way, custom use of the latter retains additional auto-configuration logic such as the naming strategy and DDL mode to use. Closes gh-15318
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.orm.jpa;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -119,22 +120,27 @@ public abstract class JpaBaseConfiguration {
|
||||
public EntityManagerFactoryBuilder entityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter,
|
||||
ObjectProvider<PersistenceUnitManager> persistenceUnitManager,
|
||||
ObjectProvider<EntityManagerFactoryBuilderCustomizer> customizers) {
|
||||
EntityManagerFactoryBuilder builder = new EntityManagerFactoryBuilder(jpaVendorAdapter,
|
||||
this.properties.getProperties(), persistenceUnitManager.getIfAvailable());
|
||||
EntityManagerFactoryBuilder builder = new EntityManagerFactoryBuilder(jpaVendorAdapter, buildJpaProperties(),
|
||||
persistenceUnitManager.getIfAvailable());
|
||||
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return builder;
|
||||
}
|
||||
|
||||
private Map<String, ?> buildJpaProperties() {
|
||||
Map<String, Object> properties = new HashMap<>(this.properties.getProperties());
|
||||
Map<String, Object> vendorProperties = getVendorProperties();
|
||||
customizeVendorProperties(vendorProperties);
|
||||
properties.putAll(vendorProperties);
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
@ConditionalOnMissingBean({ LocalContainerEntityManagerFactoryBean.class, EntityManagerFactory.class })
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder factoryBuilder,
|
||||
PersistenceManagedTypes persistenceManagedTypes) {
|
||||
Map<String, Object> vendorProperties = getVendorProperties();
|
||||
customizeVendorProperties(vendorProperties);
|
||||
return factoryBuilder.dataSource(this.dataSource)
|
||||
.managedTypes(persistenceManagedTypes)
|
||||
.properties(vendorProperties)
|
||||
.mappingResources(getMappingResources())
|
||||
.jta(isJta())
|
||||
.build();
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConf
|
||||
import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizationAutoConfiguration;
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
|
||||
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.ContextConsumer;
|
||||
@@ -207,6 +208,18 @@ abstract class AbstractJpaAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void usesManuallyDefinedLocalContainerEntityManagerFactoryBeanUsingBuilder() {
|
||||
this.contextRunner.withPropertyValues("spring.jpa.properties.a=b")
|
||||
.withUserConfiguration(TestConfigurationWithEntityManagerFactoryBuilder.class)
|
||||
.run((context) -> {
|
||||
LocalContainerEntityManagerFactoryBean factoryBean = context
|
||||
.getBean(LocalContainerEntityManagerFactoryBean.class);
|
||||
Map<String, Object> map = factoryBean.getJpaPropertyMap();
|
||||
assertThat(map).containsEntry("configured", "manually").containsEntry("a", "b");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void usesManuallyDefinedLocalContainerEntityManagerFactoryBeanIfAvailable() {
|
||||
this.contextRunner.withUserConfiguration(TestConfigurationWithLocalContainerEntityManagerFactoryBean.class)
|
||||
@@ -380,6 +393,17 @@ abstract class AbstractJpaAutoConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class TestConfigurationWithEntityManagerFactoryBuilder extends TestConfiguration {
|
||||
|
||||
@Bean
|
||||
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder,
|
||||
DataSource dataSource) {
|
||||
return builder.dataSource(dataSource).properties(Map.of("configured", "manually")).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class TestConfigurationWithLocalContainerEntityManagerFactoryBean extends TestConfiguration {
|
||||
|
||||
|
||||
@@ -311,8 +311,8 @@ It scans entities located in the same package as `Order`.
|
||||
It is possible to map additional JPA properties using the `app.first.jpa` namespace.
|
||||
|
||||
NOTE: When you create a bean for `LocalContainerEntityManagerFactoryBean` yourself, any customization that was applied during the creation of the auto-configured `LocalContainerEntityManagerFactoryBean` is lost.
|
||||
For example, in the case of Hibernate, any properties under the `spring.jpa.hibernate` prefix will not be automatically applied to your `LocalContainerEntityManagerFactoryBean`.
|
||||
If you were relying on these properties for configuring things like the naming strategy or the DDL mode, you will need to explicitly configure that when creating the `LocalContainerEntityManagerFactoryBean` bean.
|
||||
Make sure to use the auto-configured `EntityManagerFactoryBuilder` to retain JPA and vendor properties.
|
||||
This is particularly important if you were relying on `spring.jpa.*` properties for configuring things like the naming strategy or the DDL mode.
|
||||
|
||||
You should provide a similar configuration for any additional data sources for which you need JPA access.
|
||||
To complete the picture, you need to configure a `JpaTransactionManager` for each `EntityManagerFactory` as well.
|
||||
|
||||
Reference in New Issue
Block a user