Adapt EntityManagerFactoryBuilder to work with multiple data sources
This commit allows EntityManagerFactoryBuilder to provide the JPA properties to use according to the DataSource used to build the EntityManagerFactory. Previously the JPA properties were computed only once based on the primary data source, which was a problem since its default DDL setting may be different. EntityManagerFactoryBuilder takes a function that provides the JPA properties based on a data source, rather than the properties themselves. Constructors with the previous variant have been deprecated as a result. Closes gh-44516
This commit is contained in:
parent
d097870de5
commit
e06244d007
|
@ -16,8 +16,8 @@
|
|||
|
||||
package org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
|
@ -194,9 +194,10 @@ class HibernateMetricsAutoConfigurationTests {
|
|||
}
|
||||
|
||||
private LocalContainerEntityManagerFactoryBean createSessionFactory(DataSource ds) {
|
||||
Map<String, String> jpaProperties = new HashMap<>();
|
||||
jpaProperties.put("hibernate.generate_statistics", "true");
|
||||
return new EntityManagerFactoryBuilder(new HibernateJpaVendorAdapter(), jpaProperties, null).dataSource(ds)
|
||||
Function<DataSource, Map<String, ?>> jpaPropertiesFactory = (dataSource) -> Map
|
||||
.of("hibernate.generate_statistics", "true");
|
||||
return new EntityManagerFactoryBuilder(new HibernateJpaVendorAdapter(), jpaPropertiesFactory, null)
|
||||
.dataSource(ds)
|
||||
.packages(PACKAGE_CLASSES)
|
||||
.build();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -138,8 +138,8 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> getVendorProperties() {
|
||||
Supplier<String> defaultDdlMode = () -> this.defaultDdlAutoProvider.getDefaultDdlAuto(getDataSource());
|
||||
protected Map<String, Object> getVendorProperties(DataSource dataSource) {
|
||||
Supplier<String> defaultDdlMode = () -> this.defaultDdlAutoProvider.getDefaultDdlAuto(dataSource);
|
||||
return new LinkedHashMap<>(this.hibernateProperties.determineHibernateProperties(
|
||||
getProperties().getProperties(), new HibernateSettings().ddlAuto(defaultDdlMode)
|
||||
.hibernatePropertiesCustomizers(this.hibernatePropertiesCustomizers)));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -120,15 +120,15 @@ public abstract class JpaBaseConfiguration {
|
|||
public EntityManagerFactoryBuilder entityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter,
|
||||
ObjectProvider<PersistenceUnitManager> persistenceUnitManager,
|
||||
ObjectProvider<EntityManagerFactoryBuilderCustomizer> customizers) {
|
||||
EntityManagerFactoryBuilder builder = new EntityManagerFactoryBuilder(jpaVendorAdapter, buildJpaProperties(),
|
||||
persistenceUnitManager.getIfAvailable());
|
||||
EntityManagerFactoryBuilder builder = new EntityManagerFactoryBuilder(jpaVendorAdapter,
|
||||
this::buildJpaProperties, persistenceUnitManager.getIfAvailable());
|
||||
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return builder;
|
||||
}
|
||||
|
||||
private Map<String, ?> buildJpaProperties() {
|
||||
private Map<String, ?> buildJpaProperties(DataSource dataSource) {
|
||||
Map<String, Object> properties = new HashMap<>(this.properties.getProperties());
|
||||
Map<String, Object> vendorProperties = getVendorProperties();
|
||||
Map<String, Object> vendorProperties = getVendorProperties(dataSource);
|
||||
customizeVendorProperties(vendorProperties);
|
||||
properties.putAll(vendorProperties);
|
||||
return properties;
|
||||
|
@ -148,7 +148,24 @@ public abstract class JpaBaseConfiguration {
|
|||
|
||||
protected abstract AbstractJpaVendorAdapter createJpaVendorAdapter();
|
||||
|
||||
protected abstract Map<String, Object> getVendorProperties();
|
||||
/**
|
||||
* Return the vendor-specific properties for the given {@link DataSource}.
|
||||
* @param dataSource the data source
|
||||
* @return the vendor properties
|
||||
* @since 3.4.4
|
||||
*/
|
||||
protected abstract Map<String, Object> getVendorProperties(DataSource dataSource);
|
||||
|
||||
/**
|
||||
* Return the vendor-specific properties.
|
||||
* @return the vendor properties
|
||||
* @deprecated since 3.4.4 for removal in 3.6.0 in favor of
|
||||
* {@link #getVendorProperties(DataSource)}
|
||||
*/
|
||||
@Deprecated(since = "3.4.4", forRemoval = true)
|
||||
protected Map<String, Object> getVendorProperties() {
|
||||
return getVendorProperties(getDataSource());
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize vendor properties before they are used. Allows for post-processing (for
|
||||
|
|
|
@ -65,11 +65,14 @@ import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration.Fly
|
|||
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration.OracleFlywayConfigurationCustomizer;
|
||||
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration.PostgresqlFlywayConfigurationCustomizer;
|
||||
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration.SqlServerFlywayConfigurationCustomizer;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.boot.jdbc.EmbeddedDatabaseConnection;
|
||||
import org.springframework.boot.jdbc.SchemaManagement;
|
||||
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
|
@ -489,6 +492,36 @@ class FlywayAutoConfigurationTests {
|
|||
.run((context) -> assertThat(context).hasNotFailed());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMetaInfPersistenceXmlResource
|
||||
void jpaApplyDdl() {
|
||||
this.contextRunner
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class))
|
||||
.run((context) -> {
|
||||
Map<String, Object> jpaProperties = context.getBean(LocalContainerEntityManagerFactoryBean.class)
|
||||
.getJpaPropertyMap();
|
||||
assertThat(jpaProperties).doesNotContainKey("hibernate.hbm2ddl.auto");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMetaInfPersistenceXmlResource
|
||||
void jpaAndMultipleDataSourcesApplyDdl() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(HibernateJpaAutoConfiguration.class))
|
||||
.withUserConfiguration(JpaWithMultipleDataSourcesConfiguration.class)
|
||||
.run((context) -> {
|
||||
LocalContainerEntityManagerFactoryBean normalEntityManagerFactoryBean = context
|
||||
.getBean("&normalEntityManagerFactory", LocalContainerEntityManagerFactoryBean.class);
|
||||
assertThat(normalEntityManagerFactoryBean.getJpaPropertyMap()).containsEntry("configured", "normal")
|
||||
.containsEntry("hibernate.hbm2ddl.auto", "create-drop");
|
||||
LocalContainerEntityManagerFactoryBean flywayEntityManagerFactoryBean = context
|
||||
.getBean("&flywayEntityManagerFactory", LocalContainerEntityManagerFactoryBean.class);
|
||||
assertThat(flywayEntityManagerFactoryBean.getJpaPropertyMap()).containsEntry("configured", "flyway")
|
||||
.doesNotContainKey("hibernate.hbm2ddl.auto");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customFlywayWithJdbc() {
|
||||
this.contextRunner
|
||||
|
@ -962,6 +995,13 @@ class FlywayAutoConfigurationTests {
|
|||
};
|
||||
}
|
||||
|
||||
private static Map<String, ?> configureJpaProperties() {
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put("configured", "manually");
|
||||
properties.put("hibernate.transaction.jta.platform", NoJtaPlatform.INSTANCE);
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class FlywayDataSourceConfiguration {
|
||||
|
||||
|
@ -1057,10 +1097,8 @@ class FlywayAutoConfigurationTests {
|
|||
|
||||
@Bean
|
||||
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource dataSource) {
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put("configured", "manually");
|
||||
properties.put("hibernate.transaction.jta.platform", NoJtaPlatform.INSTANCE);
|
||||
return new EntityManagerFactoryBuilder(new HibernateJpaVendorAdapter(), properties, null)
|
||||
return new EntityManagerFactoryBuilder(new HibernateJpaVendorAdapter(), (ds) -> configureJpaProperties(),
|
||||
null)
|
||||
.dataSource(dataSource)
|
||||
.build();
|
||||
}
|
||||
|
@ -1083,16 +1121,54 @@ class FlywayAutoConfigurationTests {
|
|||
|
||||
@Bean
|
||||
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put("configured", "manually");
|
||||
properties.put("hibernate.transaction.jta.platform", NoJtaPlatform.INSTANCE);
|
||||
return new EntityManagerFactoryBuilder(new HibernateJpaVendorAdapter(), properties, null)
|
||||
return new EntityManagerFactoryBuilder(new HibernateJpaVendorAdapter(),
|
||||
(datasource) -> configureJpaProperties(), null)
|
||||
.dataSource(this.dataSource)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class JpaWithMultipleDataSourcesConfiguration {
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
DataSource normalDataSource() {
|
||||
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseConnection.HSQLDB.getType())
|
||||
.generateUniqueName(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
LocalContainerEntityManagerFactoryBean normalEntityManagerFactory(EntityManagerFactoryBuilder builder,
|
||||
DataSource normalDataSource) {
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put("configured", "normal");
|
||||
properties.put("hibernate.transaction.jta.platform", NoJtaPlatform.INSTANCE);
|
||||
return builder.dataSource(normalDataSource).properties(properties).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@FlywayDataSource
|
||||
DataSource flywayDataSource() {
|
||||
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseConnection.HSQLDB.getType())
|
||||
.generateUniqueName(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
LocalContainerEntityManagerFactoryBean flywayEntityManagerFactory(EntityManagerFactoryBuilder builder,
|
||||
@FlywayDataSource DataSource flywayDataSource) {
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put("configured", "flyway");
|
||||
properties.put("hibernate.transaction.jta.platform", NoJtaPlatform.INSTANCE);
|
||||
return builder.dataSource(flywayDataSource).properties(properties).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomFlywayWithJdbcConfiguration {
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.liquibase;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
@ -26,6 +27,7 @@ import java.nio.file.Files;
|
|||
import java.nio.file.Path;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
|
@ -33,6 +35,10 @@ import java.util.function.Consumer;
|
|||
import javax.sql.DataSource;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import liquibase.Liquibase;
|
||||
import liquibase.UpdateSummaryEnum;
|
||||
import liquibase.UpdateSummaryOutputEnum;
|
||||
|
@ -40,6 +46,7 @@ import liquibase.command.core.helpers.ShowSummaryArgument;
|
|||
import liquibase.integration.spring.Customizer;
|
||||
import liquibase.integration.spring.SpringLiquibase;
|
||||
import liquibase.ui.UIServiceEnum;
|
||||
import org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
@ -49,6 +56,7 @@ import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
|
|||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails;
|
||||
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
|
||||
|
@ -56,6 +64,8 @@ import org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration;
|
|||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration.LiquibaseAutoConfigurationRuntimeHints;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.boot.jdbc.EmbeddedDatabaseConnection;
|
||||
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
@ -71,6 +81,7 @@ import org.springframework.jdbc.datasource.SimpleDriverDataSource;
|
|||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
@ -549,6 +560,38 @@ class LiquibaseAutoConfigurationTests {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithDbChangelogMasterYamlResource
|
||||
@WithMetaInfPersistenceXmlResource
|
||||
void jpaApplyDdl() {
|
||||
this.contextRunner
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class))
|
||||
.run((context) -> {
|
||||
Map<String, Object> jpaProperties = context.getBean(LocalContainerEntityManagerFactoryBean.class)
|
||||
.getJpaPropertyMap();
|
||||
assertThat(jpaProperties).doesNotContainKey("hibernate.hbm2ddl.auto");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithDbChangelogMasterYamlResource
|
||||
@WithMetaInfPersistenceXmlResource
|
||||
void jpaAndMultipleDataSourcesApplyDdl() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(HibernateJpaAutoConfiguration.class))
|
||||
.withUserConfiguration(JpaWithMultipleDataSourcesConfiguration.class)
|
||||
.run((context) -> {
|
||||
LocalContainerEntityManagerFactoryBean normalEntityManagerFactoryBean = context
|
||||
.getBean("&normalEntityManagerFactory", LocalContainerEntityManagerFactoryBean.class);
|
||||
assertThat(normalEntityManagerFactoryBean.getJpaPropertyMap()).containsEntry("configured", "normal")
|
||||
.containsEntry("hibernate.hbm2ddl.auto", "create-drop");
|
||||
LocalContainerEntityManagerFactoryBean liquibaseEntityManagerFactory = context
|
||||
.getBean("&liquibaseEntityManagerFactory", LocalContainerEntityManagerFactoryBean.class);
|
||||
assertThat(liquibaseEntityManagerFactory.getJpaPropertyMap()).containsEntry("configured", "liquibase")
|
||||
.doesNotContainKey("hibernate.hbm2ddl.auto");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithDbChangelogMasterYamlResource
|
||||
void userConfigurationJdbcTemplateDependency() {
|
||||
|
@ -649,6 +692,46 @@ class LiquibaseAutoConfigurationTests {
|
|||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class JpaWithMultipleDataSourcesConfiguration {
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
DataSource normalDataSource() {
|
||||
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseConnection.HSQLDB.getType())
|
||||
.generateUniqueName(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
LocalContainerEntityManagerFactoryBean normalEntityManagerFactory(EntityManagerFactoryBuilder builder,
|
||||
DataSource normalDataSource) {
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put("configured", "normal");
|
||||
properties.put("hibernate.transaction.jta.platform", NoJtaPlatform.INSTANCE);
|
||||
return builder.dataSource(normalDataSource).properties(properties).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@LiquibaseDataSource
|
||||
DataSource liquibaseDataSource() {
|
||||
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseConnection.HSQLDB.getType())
|
||||
.generateUniqueName(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
LocalContainerEntityManagerFactoryBean liquibaseEntityManagerFactory(EntityManagerFactoryBuilder builder,
|
||||
@LiquibaseDataSource DataSource liquibaseDataSource) {
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put("configured", "liquibase");
|
||||
properties.put("hibernate.transaction.jta.platform", NoJtaPlatform.INSTANCE);
|
||||
return builder.dataSource(liquibaseDataSource).properties(properties).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CustomDataSourceConfiguration {
|
||||
|
||||
|
@ -785,4 +868,74 @@ class LiquibaseAutoConfigurationTests {
|
|||
|
||||
}
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@WithResource(name = "META-INF/persistence.xml",
|
||||
content = """
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence https://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
|
||||
<persistence-unit name="manually-configured">
|
||||
<class>org.springframework.boot.autoconfigure.flyway.FlywayAutoConfigurationTests$City</class>
|
||||
<exclude-unlisted-classes>true</exclude-unlisted-classes>
|
||||
</persistence-unit>
|
||||
</persistence>
|
||||
""")
|
||||
@interface WithMetaInfPersistenceXmlResource {
|
||||
|
||||
}
|
||||
|
||||
@Entity
|
||||
public static class City implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String state;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String country;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String map;
|
||||
|
||||
protected City() {
|
||||
}
|
||||
|
||||
City(String name, String state, String country, String map) {
|
||||
this.name = name;
|
||||
this.state = state;
|
||||
this.country = country;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
public String getCountry() {
|
||||
return this.country;
|
||||
}
|
||||
|
||||
public String getMap() {
|
||||
return this.map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName() + "," + getState() + "," + getCountry();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -81,7 +81,8 @@ class CustomHibernateJpaAutoConfigurationTests {
|
|||
.withPropertyValues("spring.datasource.url:jdbc:h2:mem:naming-strategy-beans")
|
||||
.run((context) -> {
|
||||
HibernateJpaConfiguration jpaConfiguration = context.getBean(HibernateJpaConfiguration.class);
|
||||
Map<String, Object> hibernateProperties = jpaConfiguration.getVendorProperties();
|
||||
Map<String, Object> hibernateProperties = jpaConfiguration
|
||||
.getVendorProperties(context.getBean(DataSource.class));
|
||||
assertThat(hibernateProperties).containsEntry("hibernate.implicit_naming_strategy",
|
||||
NamingStrategyConfiguration.implicitNamingStrategy);
|
||||
assertThat(hibernateProperties).containsEntry("hibernate.physical_naming_strategy",
|
||||
|
@ -93,7 +94,8 @@ class CustomHibernateJpaAutoConfigurationTests {
|
|||
void hibernatePropertiesCustomizersAreAppliedInOrder() {
|
||||
this.contextRunner.withUserConfiguration(HibernatePropertiesCustomizerConfiguration.class).run((context) -> {
|
||||
HibernateJpaConfiguration jpaConfiguration = context.getBean(HibernateJpaConfiguration.class);
|
||||
Map<String, Object> hibernateProperties = jpaConfiguration.getVendorProperties();
|
||||
Map<String, Object> hibernateProperties = jpaConfiguration
|
||||
.getVendorProperties(context.getBean(DataSource.class));
|
||||
assertThat(hibernateProperties).containsEntry("test.counter", 2);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@ import org.springframework.boot.test.context.runner.ContextConsumer;
|
|||
import org.springframework.boot.testsupport.classpath.resources.WithResource;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
|
@ -399,8 +400,7 @@ class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTes
|
|||
@Test
|
||||
void physicalNamingStrategyCanBeUsed() {
|
||||
contextRunner().withUserConfiguration(TestPhysicalNamingStrategyConfiguration.class).run((context) -> {
|
||||
Map<String, Object> hibernateProperties = context.getBean(HibernateJpaConfiguration.class)
|
||||
.getVendorProperties();
|
||||
Map<String, Object> hibernateProperties = getVendorProperties(context);
|
||||
assertThat(hibernateProperties)
|
||||
.contains(entry("hibernate.physical_naming_strategy", context.getBean("testPhysicalNamingStrategy")));
|
||||
assertThat(hibernateProperties).doesNotContainKeys("hibernate.ejb.naming_strategy");
|
||||
|
@ -410,8 +410,7 @@ class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTes
|
|||
@Test
|
||||
void implicitNamingStrategyCanBeUsed() {
|
||||
contextRunner().withUserConfiguration(TestImplicitNamingStrategyConfiguration.class).run((context) -> {
|
||||
Map<String, Object> hibernateProperties = context.getBean(HibernateJpaConfiguration.class)
|
||||
.getVendorProperties();
|
||||
Map<String, Object> hibernateProperties = getVendorProperties(context);
|
||||
assertThat(hibernateProperties)
|
||||
.contains(entry("hibernate.implicit_naming_strategy", context.getBean("testImplicitNamingStrategy")));
|
||||
assertThat(hibernateProperties).doesNotContainKeys("hibernate.ejb.naming_strategy");
|
||||
|
@ -426,8 +425,7 @@ class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTes
|
|||
.withPropertyValues("spring.jpa.hibernate.naming.physical-strategy:com.example.Physical",
|
||||
"spring.jpa.hibernate.naming.implicit-strategy:com.example.Implicit")
|
||||
.run((context) -> {
|
||||
Map<String, Object> hibernateProperties = context.getBean(HibernateJpaConfiguration.class)
|
||||
.getVendorProperties();
|
||||
Map<String, Object> hibernateProperties = getVendorProperties(context);
|
||||
assertThat(hibernateProperties).contains(
|
||||
entry("hibernate.physical_naming_strategy", context.getBean("testPhysicalNamingStrategy")),
|
||||
entry("hibernate.implicit_naming_strategy", context.getBean("testImplicitNamingStrategy")));
|
||||
|
@ -443,8 +441,7 @@ class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTes
|
|||
.withPropertyValues("spring.jpa.hibernate.naming.physical-strategy:com.example.Physical",
|
||||
"spring.jpa.hibernate.naming.implicit-strategy:com.example.Implicit")
|
||||
.run((context) -> {
|
||||
Map<String, Object> hibernateProperties = context.getBean(HibernateJpaConfiguration.class)
|
||||
.getVendorProperties();
|
||||
Map<String, Object> hibernateProperties = getVendorProperties(context);
|
||||
TestHibernatePropertiesCustomizerConfiguration configuration = context
|
||||
.getBean(TestHibernatePropertiesCustomizerConfiguration.class);
|
||||
assertThat(hibernateProperties).contains(
|
||||
|
@ -536,8 +533,11 @@ class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTes
|
|||
|
||||
private ContextConsumer<AssertableApplicationContext> vendorProperties(
|
||||
Consumer<Map<String, Object>> vendorProperties) {
|
||||
return (context) -> vendorProperties
|
||||
.accept(context.getBean(HibernateJpaConfiguration.class).getVendorProperties());
|
||||
return (context) -> vendorProperties.accept(getVendorProperties(context));
|
||||
}
|
||||
|
||||
private static Map<String, Object> getVendorProperties(ConfigurableApplicationContext context) {
|
||||
return context.getBean(HibernateJpaConfiguration.class).getVendorProperties(context.getBean(DataSource.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,6 +16,10 @@
|
|||
|
||||
package org.springframework.boot.docs.howto.dataaccess.usemultipleentitymanagers;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
@ -48,7 +52,9 @@ public class MyAdditionalEntityManagerFactoryConfiguration {
|
|||
|
||||
private EntityManagerFactoryBuilder createEntityManagerFactoryBuilder(JpaProperties jpaProperties) {
|
||||
JpaVendorAdapter jpaVendorAdapter = createJpaVendorAdapter(jpaProperties);
|
||||
return new EntityManagerFactoryBuilder(jpaVendorAdapter, jpaProperties.getProperties(), null);
|
||||
Function<DataSource, Map<String, ?>> jpaPropertiesFactory = (dataSource) -> createJpaProperties(dataSource,
|
||||
jpaProperties.getProperties());
|
||||
return new EntityManagerFactoryBuilder(jpaVendorAdapter, jpaPropertiesFactory, null);
|
||||
}
|
||||
|
||||
private JpaVendorAdapter createJpaVendorAdapter(JpaProperties jpaProperties) {
|
||||
|
@ -56,4 +62,10 @@ public class MyAdditionalEntityManagerFactoryConfiguration {
|
|||
return new HibernateJpaVendorAdapter();
|
||||
}
|
||||
|
||||
private Map<String, ?> createJpaProperties(DataSource dataSource, Map<String, ?> existingProperties) {
|
||||
Map<String, ?> jpaProperties = new LinkedHashMap<>(existingProperties);
|
||||
// ... map JPA properties that require the DataSource (e.g. DDL flags)
|
||||
return jpaProperties;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
package org.springframework.boot.docs.howto.dataaccess.usemultipleentitymanagers
|
||||
|
||||
import javax.sql.DataSource
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
|
@ -27,6 +25,7 @@ import org.springframework.context.annotation.Configuration
|
|||
import org.springframework.orm.jpa.JpaVendorAdapter
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
|
||||
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter
|
||||
import javax.sql.DataSource
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
|
@ -51,7 +50,9 @@ class MyAdditionalEntityManagerFactoryConfiguration {
|
|||
|
||||
private fun createEntityManagerFactoryBuilder(jpaProperties: JpaProperties): EntityManagerFactoryBuilder {
|
||||
val jpaVendorAdapter = createJpaVendorAdapter(jpaProperties)
|
||||
return EntityManagerFactoryBuilder(jpaVendorAdapter, jpaProperties.properties, null)
|
||||
val jpaPropertiesFactory = { dataSource: DataSource ->
|
||||
createJpaProperties(dataSource, jpaProperties.properties) }
|
||||
return EntityManagerFactoryBuilder(jpaVendorAdapter, jpaPropertiesFactory, null)
|
||||
}
|
||||
|
||||
private fun createJpaVendorAdapter(jpaProperties: JpaProperties): JpaVendorAdapter {
|
||||
|
@ -59,4 +60,10 @@ class MyAdditionalEntityManagerFactoryConfiguration {
|
|||
return HibernateJpaVendorAdapter()
|
||||
}
|
||||
|
||||
private fun createJpaProperties(dataSource: DataSource, existingProperties: Map<String, *>): Map<String, *> {
|
||||
val jpaProperties: Map<String, *> = LinkedHashMap(existingProperties)
|
||||
// ... map JPA properties that require the DataSource (e.g. DDL flags)
|
||||
return jpaProperties
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -22,6 +22,7 @@ import java.util.HashSet;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
|
@ -54,7 +55,7 @@ public class EntityManagerFactoryBuilder {
|
|||
|
||||
private final PersistenceUnitManager persistenceUnitManager;
|
||||
|
||||
private final Map<String, Object> jpaProperties;
|
||||
private final Function<DataSource, Map<String, ?>> jpaPropertiesFactory;
|
||||
|
||||
private final URL persistenceUnitRootLocation;
|
||||
|
||||
|
@ -62,6 +63,42 @@ public class EntityManagerFactoryBuilder {
|
|||
|
||||
private PersistenceUnitPostProcessor[] persistenceUnitPostProcessors;
|
||||
|
||||
/**
|
||||
* Create a new instance passing in the common pieces that will be shared if multiple
|
||||
* EntityManagerFactory instances are created.
|
||||
* @param jpaVendorAdapter a vendor adapter
|
||||
* @param jpaPropertiesFactory the JPA properties to be passed to the persistence
|
||||
* provider, based on the {@linkplain #dataSource(DataSource) configured data source}
|
||||
* @param persistenceUnitManager optional source of persistence unit information (can
|
||||
* be null)
|
||||
* @since 3.4.4
|
||||
*/
|
||||
public EntityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter,
|
||||
Function<DataSource, Map<String, ?>> jpaPropertiesFactory, PersistenceUnitManager persistenceUnitManager) {
|
||||
this(jpaVendorAdapter, jpaPropertiesFactory, persistenceUnitManager, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance passing in the common pieces that will be shared if multiple
|
||||
* EntityManagerFactory instances are created.
|
||||
* @param jpaVendorAdapter a vendor adapter
|
||||
* @param jpaPropertiesFactory the JPA properties to be passed to the persistence
|
||||
* provider, based on the {@linkplain #dataSource(DataSource) configured data source}
|
||||
* @param persistenceUnitManager optional source of persistence unit information (can
|
||||
* be null)
|
||||
* @param persistenceUnitRootLocation the persistence unit root location to use as a
|
||||
* fallback or {@code null}
|
||||
* @since 3.4.4
|
||||
*/
|
||||
public EntityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter,
|
||||
Function<DataSource, Map<String, ?>> jpaPropertiesFactory, PersistenceUnitManager persistenceUnitManager,
|
||||
URL persistenceUnitRootLocation) {
|
||||
this.jpaVendorAdapter = jpaVendorAdapter;
|
||||
this.persistenceUnitManager = persistenceUnitManager;
|
||||
this.jpaPropertiesFactory = jpaPropertiesFactory;
|
||||
this.persistenceUnitRootLocation = persistenceUnitRootLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance passing in the common pieces that will be shared if multiple
|
||||
* EntityManagerFactory instances are created.
|
||||
|
@ -69,10 +106,13 @@ public class EntityManagerFactoryBuilder {
|
|||
* @param jpaProperties the JPA properties to be passed to the persistence provider
|
||||
* @param persistenceUnitManager optional source of persistence unit information (can
|
||||
* be null)
|
||||
* @deprecated since 3.4.4 for removal in 3.6.0 in favor of
|
||||
* {@link #EntityManagerFactoryBuilder(JpaVendorAdapter, Function, PersistenceUnitManager)}
|
||||
*/
|
||||
@Deprecated(since = "3.4.4", forRemoval = true)
|
||||
public EntityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter, Map<String, ?> jpaProperties,
|
||||
PersistenceUnitManager persistenceUnitManager) {
|
||||
this(jpaVendorAdapter, jpaProperties, persistenceUnitManager, null);
|
||||
this(jpaVendorAdapter, (datasource) -> jpaProperties, persistenceUnitManager, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,15 +125,21 @@ public class EntityManagerFactoryBuilder {
|
|||
* @param persistenceUnitRootLocation the persistence unit root location to use as a
|
||||
* fallback or {@code null}
|
||||
* @since 1.4.1
|
||||
* @deprecated since 3.4.4 for removal in 3.6.0 in favor of
|
||||
* {@link #EntityManagerFactoryBuilder(JpaVendorAdapter, Function, PersistenceUnitManager, URL)}
|
||||
*/
|
||||
@Deprecated(since = "3.4.4", forRemoval = true)
|
||||
public EntityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter, Map<String, ?> jpaProperties,
|
||||
PersistenceUnitManager persistenceUnitManager, URL persistenceUnitRootLocation) {
|
||||
this.jpaVendorAdapter = jpaVendorAdapter;
|
||||
this.persistenceUnitManager = persistenceUnitManager;
|
||||
this.jpaProperties = new LinkedHashMap<>(jpaProperties);
|
||||
this.persistenceUnitRootLocation = persistenceUnitRootLocation;
|
||||
this(jpaVendorAdapter, (datasource) -> jpaProperties, persistenceUnitManager, persistenceUnitRootLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Builder} for a {@code EntityManagerFactory} using the settings
|
||||
* of the given instance, and the given {@link DataSource}.
|
||||
* @param dataSource the data source to use
|
||||
* @return a builder to create an {@code EntityManagerFactory}
|
||||
*/
|
||||
public Builder dataSource(DataSource dataSource) {
|
||||
return new Builder(dataSource);
|
||||
}
|
||||
|
@ -255,7 +301,8 @@ public class EntityManagerFactoryBuilder {
|
|||
else {
|
||||
entityManagerFactoryBean.setPackagesToScan(this.packagesToScan);
|
||||
}
|
||||
entityManagerFactoryBean.getJpaPropertyMap().putAll(EntityManagerFactoryBuilder.this.jpaProperties);
|
||||
Map<String, ?> jpaProperties = EntityManagerFactoryBuilder.this.jpaPropertiesFactory.apply(this.dataSource);
|
||||
entityManagerFactoryBean.getJpaPropertyMap().putAll(new LinkedHashMap<>(jpaProperties));
|
||||
entityManagerFactoryBean.getJpaPropertyMap().putAll(this.properties);
|
||||
if (!ObjectUtils.isEmpty(this.mappingResources)) {
|
||||
entityManagerFactoryBean.setMappingResources(this.mappingResources);
|
||||
|
|
Loading…
Reference in New Issue