Unsatisfied dependency with Panache and Multiple Datasources

278 views Asked by At

What I'm trying to do

I'm creating a Vaadin application with Quarkus, and while trying to connect multiple datasources, an error was thrown :

2023-08-06 13:24:47,765 ERROR [io.qua.dep.dev.IsolatedDevModeMain] (main) Failed to start quarkus: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
        [error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: jakarta.enterprise.inject.spi.DeploymentException: Found 3 deployment problems: 
[1] Unsatisfied dependency for type jakarta.persistence.EntityManagerFactory and qualifiers [@Default]
        - java member: io.quarkus.security.jpa.runtime.JpaTrustedIdentityProvider#entityManagerFactory
        - declared on CLASS bean [types=[io.quarkus.security.jpa.runtime.JpaTrustedIdentityProvider, io.quarkus.security.identity.IdentityProvider<io.quarkus.security.identity.request.TrustedAuthenticationRequest>, com.database.model.crm.CrmUser__JpaTrustedIdentityProviderImpl, java.lang.Object], qualifiers=[@Default, @Any], target=com.database.model.crm.CrmUser__JpaTrustedIdentityProviderImpl]
        The following beans match by type, but none have matching qualifiers:
                - Bean [class=org.hibernate.SessionFactory, qualifiers=[@Any, @io.quarkus.hibernate.orm.PersistenceUnit("default"), @Named("default")]]
                - Bean [class=org.hibernate.SessionFactory, qualifiers=[@Any, @Named("reservation"), @io.quarkus.hibernate.orm.PersistenceUnit("reservation")]]
[2] Unsatisfied dependency for type jakarta.persistence.EntityManagerFactory and qualifiers [@Default]
        - java member: io.quarkus.security.jpa.runtime.JpaIdentityProvider#entityManagerFactory
        - declared on CLASS bean [types=[io.quarkus.security.jpa.runtime.JpaIdentityProvider, io.quarkus.security.identity.IdentityProvider<io.quarkus.security.identity.request.UsernamePasswordAuthenticationRequest>, java.lang.Object, com.database.model.crm.CrmUser__JpaIdentityProviderImpl], qualifiers=[@Default, @Any], target=com.database.model.crm.CrmUser__JpaIdentityProviderImpl]
        The following beans match by type, but none have matching qualifiers:
                - Bean [class=org.hibernate.SessionFactory, qualifiers=[@Any, @io.quarkus.hibernate.orm.PersistenceUnit("default"), @Named("default")]]
                - Bean [class=org.hibernate.SessionFactory, qualifiers=[@Any, @Named("reservation"), @io.quarkus.hibernate.orm.PersistenceUnit("reservation")]]
[3] Unsatisfied dependency for type io.quarkus.security.identity.AuthenticationRequestContext and qualifiers [@Default]
        - java member: com.ui.configuration.UserAugmentor#augment():context
        - declared on PRODUCER METHOD bean [types=[java.lang.Object, io.smallrye.mutiny.Uni<io.quarkus.security.identity.SecurityIdentity>], qualifiers=[@Any, @PersistenceUnitExtension], target=io.smallrye.mutiny.Uni<io.quarkus.security.identity.SecurityIdentity> augment(io.quarkus.security.identity.SecurityIdentity identity, io.quarkus.security.identity.AuthenticationRequestContext context), declaringBean=com.ui.configuration.UserAugmentor]

My datasources configuration look like this :

quarkus.datasource.default... # Default datasource config
quarkus.datasource.reservation... # Reservation datasource config

quarkus.hibernate-orm.default.datasource=default # Orm Default mapping
quarkus.hibernate-orm.reservation.datasource=reservation # Orm reservation mapping

And my entities are correctly associated to according datasource with package-info.java :

@PersistenceUnit("default")
package com.database.model.crm;

import io.quarkus.hibernate.orm.PersistenceUnit;

and

@PersistenceUnit("reservation")
package com.database.model.reservation;

import io.quarkus.hibernate.orm.PersistenceUnit;

I already tried a few things :

First i tried adding relevant annotation @PersistenceUnitExtension to my UserAugmentor responsible of security identity providing inside my app :

@PersistenceUnitExtension
@RequestScoped
public class UserAugmentor implements SecurityIdentityAugmentor {
...
}

Then, as I was using Active Record Pattern, I tried switching to Repository Pattern to add @PersistenceUnitExtension on the injected repository :

@Inject
@PersistenceUnitExtension
CrmUserRepository crmUserRepository;

None of this worked unfortunately. I have read every documentation available and at this point I have no idea what's could be the solution.

Could someone point me in the right direction please ? Did I forgot something ?

Thank you for reading.

Edit 1

After playing around I think i found the origin of the problem here in JpaIdentityProvider where EntityManagerFactory is injected.

public abstract class JpaIdentityProvider implements IdentityProvider<UsernamePasswordAuthenticationRequest> {

    private static Logger log = Logger.getLogger(JpaIdentityProvider.class);

    @Inject
    EntityManagerFactory entityManagerFactory; // I think this one is the origin

    public JpaIdentityProvider() {}
...

Do you think this may be a bug ?

Edit 2

Previous error is gone, but suggested configuration is not working yet. I simply cannot annotate package-info.java with @PersistenceUnit with no value.

It gives me 'value' missing though required. I also tried using @PersistenceUnit("<default>") as its the default value specified in annotation.

This gave me the following error :

Model classes are defined for the default persistence unit <default> but configured datasource <default> not found: the default EntityManagerFactory will not be created. To solve this, configure the default datasource. Refer to https://quarkus.io/guides/datasource for guidance.

Even with proper configuration of default datasource :

quarkus.datasource... # Default datasource config
quarkus.datasource.reservation... # Reservation datasource config

quarkus.hibernate-orm.reservation.datasource=reservation # Orm reservation mapping

Edit 3

The following error was due to bad configuration :

Model classes are defined for the default persistence unit <default> but configured datasource <default> not found: the default EntityManagerFactory will not be created. To solve this, configure the default datasource. Refer to https://quarkus.io/guides/datasource for guidance.

But I still cannot set @PersistenceUnit without value.

1

There are 1 answers

2
yrodiere On BEST ANSWER

There is not default persistence unit / datasource in your configuration as far as Quarkus is concerned. There is only a named datasource which happens to be named default. The default persistence unit / datasource doesn't have a name.

You should use this configuration:

quarkus.datasource... # Default datasource config
quarkus.datasource.reservation... # Reservation datasource config

# The default Persistence Unit will use the default datasource (no config needed)

quarkus.hibernate-orm.reservation.datasource=reservation # Orm reservation mapping

Same for annotations, you shouldn't use the name "default":

@PersistenceUnit // Note this is @io.quarkus.hibernate.orm.PersistenceUnit, not @jakarta.persistence.PersistenceUnit
package com.database.model.crm;

import io.quarkus.hibernate.orm.PersistenceUnit;

As to why quarkus-security-jpa only works with the default PU... it seems support for named datasource simply wasn't implemented yet. I opened https://github.com/quarkusio/quarkus/issues/35231 to address that. In the meantime, the configuration I gave above should work.