Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bean-based conditions do not consider factory beans correctly when determining if they are a candidate #42970

Closed
rajadilipkolli opened this issue Nov 1, 2024 · 7 comments
Assignees
Labels
type: bug A general bug
Milestone

Comments

@rajadilipkolli
Copy link
Contributor

rajadilipkolli commented Nov 1, 2024

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 :

  1. Download code from the branch qualifier
  2. Bring Postgresql and Mysql database from docker-compose.yml
  3. 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.

@rajadilipkolli rajadilipkolli changed the title Spring Boot 3.4.0-RC1 Configuration Issue with Multiple Datasources and EntityManagers Spring Boot 3.4.0-RC1 Configuration Issue with Multiple Datasources and EntityManagers using new approach Nov 1, 2024
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Nov 1, 2024
@wilkinsona wilkinsona changed the title Spring Boot 3.4.0-RC1 Configuration Issue with Multiple Datasources and EntityManagers using new approach Bean-based conditions do not consider factory beans correctly when determining if they are a candidate Nov 1, 2024
@wilkinsona wilkinsona added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Nov 1, 2024
@wilkinsona wilkinsona added this to the 3.4.x milestone Nov 1, 2024
@wilkinsona wilkinsona self-assigned this Nov 1, 2024
@wilkinsona wilkinsona modified the milestones: 3.4.x, 3.4.0 Nov 1, 2024
@rajadilipkolli
Copy link
Contributor Author

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?

@wilkinsona
Copy link
Member

wilkinsona commented Nov 1, 2024

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.

@rajadilipkolli
Copy link
Contributor Author

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

@rajadilipkolli
Copy link
Contributor Author

rajadilipkolli commented Nov 2, 2024

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);
        };
    }
}

@quaff
Copy link
Contributor

quaff commented Nov 4, 2024

It would be nice feature to support defaultCondidate =false for @ServiceConnection if possible.

I agree, and derived bean should also respect @Bean(defaultCandidate) and @Qualifier from source bean.

@quaff
Copy link
Contributor

quaff commented Nov 4, 2024

It would be nice feature to support defaultCondidate =false for @ServiceConnection if possible.

I agree, and derived bean should also respect @Bean(defaultCandidate) and @Qualifier from source bean.

I created #42978, please verify if you get a chance @rajadilipkolli

@wilkinsona
Copy link
Member

Is the bean based condition supported for @ServiceConnection ?

Not yet, no. I've opened #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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

4 participants