Fran Pedreira
Fran Pedreira

Reputation: 1

More than 1 bean of LiquibaseProperties found, when required a single bean

I am currently receiving the following error on start:

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 3 of method liquibase in org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration$LiquibaseConfiguration required a single bean, but 2 were found:
    - liquibaseConnectionDetailsForKeycloak_db: defined in unknown location
    - liquibaseConnectionDetailsForServer_db: defined in unknown location

By following the autoconfiguration class, I see that the method in question is:

@Bean
public SpringLiquibase liquibase(ObjectProvider<DataSource> dataSource,
                @LiquibaseDataSource ObjectProvider<DataSource> liquibaseDataSource, LiquibaseProperties properties,
                LiquibaseConnectionDetails connectionDetails) {...}

This way I identified that the type of the conflicting bean is LiquibaseProperties. I understand that the issue occurs because my application is being launched using a Docker Compose file, which not only runs the application but also starts Keycloak and a database for both of them. This leads to the autoconfiguration detecting two datasources. In my case, I want Liquibase to only connect to the application's data source, not Keycloak’s.

Here is the configuration in my application.properties file:

spring.datasource.url=${SERVER_DB_URL}/${SERVER_DB}
spring.datasource.username=${SERVER_DB_USER}
spring.datasource.password=${SERVER_DB_PASSWORD}
spring.datasource.driver-class-name=org.postgresql.Driver

spring.liquibase.url=${SERVER_DB_URL}/${SERVER_DB}
spring.liquibase.user=${SERVER_DB_USER}
spring.liquibase.password=${SERVER_DB_PASSWORD}
spring.liquibase.change-log=classpath:db/changelogs/changelog-master.xml

With the Keycloak db url being different obviously: jdbc:postgresql://localhost:5433.

I'm also adding my compose in case it could help:

services:

  keycloak_db:
    image: postgres
    container_name: keycloak_db
    restart: always
    ports:
      - "${KEYCLOAK_DB_PORT}:5432"
    environment:
      POSTGRES_DB: ${KEYCLOAK_DB}
      POSTGRES_USER: ${KEYCLOAK_DB_USER}
      POSTGRES_PASSWORD: ${KEYCLOAK_DB_PASSWORD}
    volumes:
      - keycloak-db-volume:/var/lib/postgresql/data

  keycloak:
    image: keycloak/keycloak
    container_name: keycloak
    restart: always
    command:
      - start-dev
    ports:
      - "${KEYCLOAK_PORT}:8080"
    environment:
      KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN}
      KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}
      KC_DB: postgres
      KC_DB_URL: jdbc:postgresql://keycloak_db/${KEYCLOAK_DB}
      KC_DB_USERNAME: ${KEYCLOAK_DB_USER}
      KC_DB_PASSWORD: ${KEYCLOAK_DB_PASSWORD}
    depends_on:
        - keycloak_db
    volumes:
      - keycloak-volume:/opt/keycloak/data/import/

  postgres:
    image: postgres
    container_name: server_db
    restart: always
    ports:
      - "${SERVER_DB_PORT}:5432"
    environment:
      POSTGRES_DB: ${SERVER_DB}
      POSTGRES_USER: ${SERVER_DB_USER}
      POSTGRES_PASSWORD: ${SERVER_DB_PASSWORD}
    depends_on:
      - keycloak
    volumes:
      - server_db_volume:/var/lib/postgresql/data

So, how can I define the specific bean to use? I've seen an tried examples, some using @Primary, but none where exactly for the case of the problem with LiquibaseProperties and so it did not work. Also, the fact that the defined location for the bean is 'unknown' also makes it more complicated.

Although at first I would like it to just ignore the ones from Keycloak, I understand that in the future it could be useful to have a way of admiting both, but my priority is to just run with the first one.

Upvotes: 0

Views: 40

Answers (1)

Fran Pedreira
Fran Pedreira

Reputation: 1

By running some tests, I found out that although I tried to specify the datasource in the application.properties, so it had no conflict when trying to select one for the liquibase bean, it was still detecting it somehow. I could prove, although only through trial and error, that it was due to the following plugin:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-docker-compose</artifactId>
    <scope>runtime</scope>
</dependency>

When I ran my app with IntelliJ, the compose was also executed, which I found great, but the "autoconfiguration" between the containers and the app made it detect the new datasource without desiring it at all.

Although I can make it work, at least for now, I still think that I lack for a way of, If I add the plugin back again, suppress the spring autoconfiguration for datasources and implement my own.

Upvotes: 0

Related Questions