I have a Spring Boot application that utilizes both Liquibase and Flyway for schema management, connecting to PostgreSQL and MySQL databases. I recently upgraded to Spring Boot 3.4.0-RC1 and it is working as expected with my code.
I have encountered below issue when attempting to simplify the configuration using the new approach as described in documentation.
Cannot resolve reference to bean 'jpaSharedEM_entityManagerFactory' while setting bean property 'entityManager'
Detailed logs can be seen in the github workflow here
Steps to Reproduce :
- Download code from the branch qualifier
- Bring Postgresql and Mysql database from
docker-compose.yml - Application should start succesfully.
Changes made to existing repository can be seen in this PR
Expected Behavior:
The application should start successfully using new approach and use Liquibase and Flyway to manage the schema for each database.
Comment From: rajadilipkolli
Hi @wilkinsona, Thanks for the fix.
I have updated my sample to use snapshot and the earlier reported issue is fixed. But when schema validation is performed. spring boot default entityManagerFactory is considering entities from other entityManagerFactory which is cardHolderEntityManagerFactory in the sample.
error
2024-11-01T18:04:32.471Z ERROR 2125 --- [boot-data-multipledatasources] [ main] j.LocalContainerEntityManagerFactoryBean : Failed to initialize JPA EntityManagerFactory: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing table [card_holder]
2024-11-01T18:04:32.472Z WARN 2125 --- [boot-data-multipledatasources] [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing table [card_holder]
card_holder table is part of cardHolderEntityManagerFactory
Am I missing any other configuration?
Comment From: wilkinsona
Thanks for trying the snapshot and confirming that it fixes the earlier reported issue.
Am I missing any other configuration?
You need to use @EntityScan to limit the packages that are scanned by the auto-configured infrastructure:
@EntityScan(basePackageClasses = Member.class)
By default, the auto-configured entity manager will use the package of your @SpringBootApplication as its base package for entity scanning. In this case, that's com.example.multipledatasources which covers both your Member entity and your CardHolder entity. By adding the @EntityScan above, you narrow down the packages covered by the auto-configured JPA infrastructure so that CardHolder entity isn't picked up.
Comment From: rajadilipkolli
Thanks @wilkinsona , It has worked.
One of the side effects of using Spring boot extensively is that it does very good work by autoconfiguring we tend to forget basics. Feeling bit embarrassed on missing basic thing.
Should we add in documentation about above basic EntityScan
Comment From: rajadilipkolli
Hi @wilkinsona , Is the bean based condition supported for @ServiceConnection ?
In my TestContainers configuration I have configured as below, I have expected that postgresql container values will be assigned to default spring.datasource. properties but whichever is started 2nd is getting set to it, so mysql values are set to spring.datasource. properties.
It would be nice feature to support defaultCondidate =false for @ServiceConnection if possible.
@TestConfiguration(proxyBeanMethods = false)
public class ContainersConfiguration {
@Qualifier("second") @Bean(defaultCandidate = false)
@ServiceConnection
MySQLContainer<?> mySQLContainer() {
return new MySQLContainer<>(DockerImageName.parse("mysql").withTag("9.1"));
}
@Bean
@ServiceConnection
PostgreSQLContainer<?> postgreSQLContainer() {
return new PostgreSQLContainer<>(DockerImageName.parse("postgres").withTag("17.0-alpine"));
}
@Bean
public DynamicPropertyRegistrar databaseProperties(@Qualifier("second") MySQLContainer<?> mySQLContainer) {
return (properties) -> {
// Connect our Spring application to our Testcontainers instances
properties.add("app.datasource.cardholder.url", mySQLContainer::getJdbcUrl);
properties.add("app.datasource.cardholder.username", mySQLContainer::getUsername);
properties.add("app.datasource.cardholder.password", mySQLContainer::getPassword);
};
}
}
Comment From: quaff
It would be nice feature to support
defaultCondidate =falsefor@ServiceConnectionif possible.
I agree, and derived bean should also respect @Bean(defaultCandidate) and @Qualifier from source bean.
Comment From: quaff
It would be nice feature to support
defaultCondidate =falsefor@ServiceConnectionif possible.I agree, and derived bean should also respect
@Bean(defaultCandidate)and@Qualifierfrom source bean.
I created https://github.com/spring-projects/spring-boot/pull/42978, please verify if you get a chance @rajadilipkolli
Comment From: wilkinsona
Is the bean based condition supported for
@ServiceConnection?
Not yet, no. I've opened https://github.com/spring-projects/spring-boot/issues/42979. Unfortunately, I don't think we can use quaff's approach and we should also consider the Docker compose side of things so that things are as conceptually similar as possible.