|
18 | 18 |
|
19 | 19 | import java.io.File;
|
20 | 20 | import java.io.IOException;
|
| 21 | +import java.io.Serializable; |
21 | 22 | import java.lang.annotation.ElementType;
|
22 | 23 | import java.lang.annotation.Retention;
|
23 | 24 | import java.lang.annotation.RetentionPolicy;
|
|
26 | 27 | import java.nio.file.Path;
|
27 | 28 | import java.sql.Connection;
|
28 | 29 | import java.sql.SQLException;
|
| 30 | +import java.util.HashMap; |
29 | 31 | import java.util.Map;
|
30 | 32 | import java.util.UUID;
|
31 | 33 | import java.util.function.Consumer;
|
32 | 34 |
|
33 | 35 | import javax.sql.DataSource;
|
34 | 36 |
|
35 | 37 | import com.zaxxer.hikari.HikariDataSource;
|
| 38 | +import jakarta.persistence.Column; |
| 39 | +import jakarta.persistence.Entity; |
| 40 | +import jakarta.persistence.GeneratedValue; |
| 41 | +import jakarta.persistence.Id; |
36 | 42 | import liquibase.Liquibase;
|
37 | 43 | import liquibase.UpdateSummaryEnum;
|
38 | 44 | import liquibase.UpdateSummaryOutputEnum;
|
39 | 45 | import liquibase.command.core.helpers.ShowSummaryArgument;
|
40 | 46 | import liquibase.integration.spring.Customizer;
|
41 | 47 | import liquibase.integration.spring.SpringLiquibase;
|
42 | 48 | import liquibase.ui.UIServiceEnum;
|
| 49 | +import org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform; |
43 | 50 | import org.junit.jupiter.api.Test;
|
44 | 51 | import org.junit.jupiter.api.extension.ExtendWith;
|
45 | 52 | import org.junit.jupiter.api.io.TempDir;
|
|
49 | 56 | import org.springframework.beans.factory.BeanCreationException;
|
50 | 57 | import org.springframework.beans.factory.config.BeanDefinition;
|
51 | 58 | import org.springframework.boot.autoconfigure.AutoConfigurations;
|
| 59 | +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; |
52 | 60 | import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
53 | 61 | import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails;
|
54 | 62 | import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
|
55 | 63 | import org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration;
|
56 | 64 | import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration.LiquibaseAutoConfigurationRuntimeHints;
|
57 | 65 | import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
58 | 66 | import org.springframework.boot.jdbc.DataSourceBuilder;
|
| 67 | +import org.springframework.boot.jdbc.EmbeddedDatabaseConnection; |
| 68 | +import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; |
59 | 69 | import org.springframework.boot.test.context.FilteredClassLoader;
|
60 | 70 | import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
61 | 71 | import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
|
71 | 81 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
|
72 | 82 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
73 | 83 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
| 84 | +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; |
74 | 85 | import org.springframework.test.util.ReflectionTestUtils;
|
75 | 86 |
|
76 | 87 | import static org.assertj.core.api.Assertions.assertThat;
|
@@ -549,6 +560,38 @@ void userConfigurationEntityManagerFactoryDependency() {
|
549 | 560 | });
|
550 | 561 | }
|
551 | 562 |
|
| 563 | + @Test |
| 564 | + @WithDbChangelogMasterYamlResource |
| 565 | + @WithMetaInfPersistenceXmlResource |
| 566 | + void jpaApplyDdl() { |
| 567 | + this.contextRunner |
| 568 | + .withConfiguration( |
| 569 | + AutoConfigurations.of(DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class)) |
| 570 | + .run((context) -> { |
| 571 | + Map<String, Object> jpaProperties = context.getBean(LocalContainerEntityManagerFactoryBean.class) |
| 572 | + .getJpaPropertyMap(); |
| 573 | + assertThat(jpaProperties).doesNotContainKey("hibernate.hbm2ddl.auto"); |
| 574 | + }); |
| 575 | + } |
| 576 | + |
| 577 | + @Test |
| 578 | + @WithDbChangelogMasterYamlResource |
| 579 | + @WithMetaInfPersistenceXmlResource |
| 580 | + void jpaAndMultipleDataSourcesApplyDdl() { |
| 581 | + this.contextRunner.withConfiguration(AutoConfigurations.of(HibernateJpaAutoConfiguration.class)) |
| 582 | + .withUserConfiguration(JpaWithMultipleDataSourcesConfiguration.class) |
| 583 | + .run((context) -> { |
| 584 | + LocalContainerEntityManagerFactoryBean normalEntityManagerFactoryBean = context |
| 585 | + .getBean("&normalEntityManagerFactory", LocalContainerEntityManagerFactoryBean.class); |
| 586 | + assertThat(normalEntityManagerFactoryBean.getJpaPropertyMap()).containsEntry("configured", "normal") |
| 587 | + .containsEntry("hibernate.hbm2ddl.auto", "create-drop"); |
| 588 | + LocalContainerEntityManagerFactoryBean liquibaseEntityManagerFactory = context |
| 589 | + .getBean("&liquibaseEntityManagerFactory", LocalContainerEntityManagerFactoryBean.class); |
| 590 | + assertThat(liquibaseEntityManagerFactory.getJpaPropertyMap()).containsEntry("configured", "liquibase") |
| 591 | + .doesNotContainKey("hibernate.hbm2ddl.auto"); |
| 592 | + }); |
| 593 | + } |
| 594 | + |
552 | 595 | @Test
|
553 | 596 | @WithDbChangelogMasterYamlResource
|
554 | 597 | void userConfigurationJdbcTemplateDependency() {
|
@@ -649,6 +692,46 @@ SpringLiquibase springLiquibase(DataSource dataSource) {
|
649 | 692 |
|
650 | 693 | }
|
651 | 694 |
|
| 695 | + @Configuration(proxyBeanMethods = false) |
| 696 | + static class JpaWithMultipleDataSourcesConfiguration { |
| 697 | + |
| 698 | + @Bean |
| 699 | + @Primary |
| 700 | + DataSource normalDataSource() { |
| 701 | + return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseConnection.HSQLDB.getType()) |
| 702 | + .generateUniqueName(true) |
| 703 | + .build(); |
| 704 | + } |
| 705 | + |
| 706 | + @Bean |
| 707 | + @Primary |
| 708 | + LocalContainerEntityManagerFactoryBean normalEntityManagerFactory(EntityManagerFactoryBuilder builder, |
| 709 | + DataSource normalDataSource) { |
| 710 | + Map<String, Object> properties = new HashMap<>(); |
| 711 | + properties.put("configured", "normal"); |
| 712 | + properties.put("hibernate.transaction.jta.platform", NoJtaPlatform.INSTANCE); |
| 713 | + return builder.dataSource(normalDataSource).properties(properties).build(); |
| 714 | + } |
| 715 | + |
| 716 | + @Bean |
| 717 | + @LiquibaseDataSource |
| 718 | + DataSource liquibaseDataSource() { |
| 719 | + return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseConnection.HSQLDB.getType()) |
| 720 | + .generateUniqueName(true) |
| 721 | + .build(); |
| 722 | + } |
| 723 | + |
| 724 | + @Bean |
| 725 | + LocalContainerEntityManagerFactoryBean liquibaseEntityManagerFactory(EntityManagerFactoryBuilder builder, |
| 726 | + @LiquibaseDataSource DataSource liquibaseDataSource) { |
| 727 | + Map<String, Object> properties = new HashMap<>(); |
| 728 | + properties.put("configured", "liquibase"); |
| 729 | + properties.put("hibernate.transaction.jta.platform", NoJtaPlatform.INSTANCE); |
| 730 | + return builder.dataSource(liquibaseDataSource).properties(properties).build(); |
| 731 | + } |
| 732 | + |
| 733 | + } |
| 734 | + |
652 | 735 | @Configuration(proxyBeanMethods = false)
|
653 | 736 | static class CustomDataSourceConfiguration {
|
654 | 737 |
|
@@ -785,4 +868,74 @@ static class CustomH2Driver extends org.h2.Driver {
|
785 | 868 |
|
786 | 869 | }
|
787 | 870 |
|
| 871 | + @Target(ElementType.METHOD) |
| 872 | + @Retention(RetentionPolicy.RUNTIME) |
| 873 | + @WithResource(name = "META-INF/persistence.xml", |
| 874 | + content = """ |
| 875 | + <?xml version="1.0" encoding="UTF-8"?> |
| 876 | + <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"> |
| 877 | + <persistence-unit name="manually-configured"> |
| 878 | + <class>org.springframework.boot.autoconfigure.flyway.FlywayAutoConfigurationTests$City</class> |
| 879 | + <exclude-unlisted-classes>true</exclude-unlisted-classes> |
| 880 | + </persistence-unit> |
| 881 | + </persistence> |
| 882 | + """) |
| 883 | + @interface WithMetaInfPersistenceXmlResource { |
| 884 | + |
| 885 | + } |
| 886 | + |
| 887 | + @Entity |
| 888 | + public static class City implements Serializable { |
| 889 | + |
| 890 | + private static final long serialVersionUID = 1L; |
| 891 | + |
| 892 | + @Id |
| 893 | + @GeneratedValue |
| 894 | + private Long id; |
| 895 | + |
| 896 | + @Column(nullable = false) |
| 897 | + private String name; |
| 898 | + |
| 899 | + @Column(nullable = false) |
| 900 | + private String state; |
| 901 | + |
| 902 | + @Column(nullable = false) |
| 903 | + private String country; |
| 904 | + |
| 905 | + @Column(nullable = false) |
| 906 | + private String map; |
| 907 | + |
| 908 | + protected City() { |
| 909 | + } |
| 910 | + |
| 911 | + City(String name, String state, String country, String map) { |
| 912 | + this.name = name; |
| 913 | + this.state = state; |
| 914 | + this.country = country; |
| 915 | + this.map = map; |
| 916 | + } |
| 917 | + |
| 918 | + public String getName() { |
| 919 | + return this.name; |
| 920 | + } |
| 921 | + |
| 922 | + public String getState() { |
| 923 | + return this.state; |
| 924 | + } |
| 925 | + |
| 926 | + public String getCountry() { |
| 927 | + return this.country; |
| 928 | + } |
| 929 | + |
| 930 | + public String getMap() { |
| 931 | + return this.map; |
| 932 | + } |
| 933 | + |
| 934 | + @Override |
| 935 | + public String toString() { |
| 936 | + return getName() + "," + getState() + "," + getCountry(); |
| 937 | + } |
| 938 | + |
| 939 | + } |
| 940 | + |
788 | 941 | }
|
0 commit comments