CurrentTenantIdentifierResolver and MultiTenantConnectionProvider don't seem to get picked up from the BeanContainer

Description

My expectation is that when an external BeanContainer is configured Hibernate would ask the BeanContainer for instances of CurrentTenantIdentifierResolver and MultiTenantConnectionProvider
This doesn’t work. I have to explicitly set these.

 

I just to try to make this work.

And it does work in the current state

But it requires explicit setting of the MULTI_TENENT_IDENTIFIER_RESOLVER via


 

Is there a reason, why Hibernate doesn’t ask the BeanContainer for instances of this class? Or is this an oversight/bug/missing feature?

Based on the referenced projects I verified that for example a entity listener is pulled from the BeanContainer backed by a Spring ApplicationContext
There are also variants of the projects in the same repository which demonstrate the same problem with the connection provider.

Attachments

1

Activity

Show:

Yoann Rodière October 7, 2024 at 8:02 AM

I don’t know the motivation for Search or for Quarkus to override the default (and IMO better) behavior of ORM, but I will follow up on this with .

In particular, I’m struggling to see why Quarkus overrides this, and so perhaps it’s simply unnecessary. If so, and if we can start using JpaCompliantLifecycleStrategy in Quarkus, then I can drop my objections to the linked pull request.

Starting a conversation on Zulip, because I have a feeling it will be long and painful: https://hibernate.zulipchat.com/#narrow/stream/132094-hibernate-orm-dev/topic/JPA-compliant.20CDI.20and.20HHH-15422

Gavin King October 4, 2024 at 6:40 PM

Oh, I realized that you guys are probably thinking that these things are just completely bog-standard CDI beans that are discovered, registered, and instantiated completely by CDI with no involvement of Hibernate at all.

But while this approach might be OK for, say CurrentTenantIdentifierResolver which is a very simple object, it doesn’t work in generalfor example, it doesn’t work for entity listeners, attribute converters, Generators, nor, in general for ConnectionProviders:

  • the CDI container doesn’t discover these things; they’re configured via annotations, and,

  • furthermore, some of them need access to the Hibernate ServiceRegistry when they’re instantiated.

So what I’m trying to do here is find an approach which works generically, for all these sorts of components, not just for two of them, and that’s easy because it’s already defined in the JPA spec, and already implemented by JpaCompliantLifecycleStrategy.

Now, having said all that, I just noticed from the code that in fact we never actually use ContainerManagedLifecycleStrategy in ORM itself, rather, we always use the JpaCompliantLifecycleStrategy. Digging further I found that:

  1. according to , WildFly does not override this behavior, but

  2. Hibernate Search apparently does, and forces the use of ContainerManagedLifecycleStrategy, and, similarly,

  3. Quarkus also forces the use of ContainerManagedLifecycleStrategy.

I don’t know the motivation for Search or for Quarkus to override the default (and IMO better) behavior of ORM, but I will follow up on this with .

In particular, I’m struggling to see why Quarkus overrides this, and so perhaps it’s simply unnecessary. If so, and if we can start using JpaCompliantLifecycleStrategy in Quarkus, then I can drop my objections to the linked pull request.

Gavin King October 4, 2024 at 12:11 PM
Edited

so these contracts can safely be constructed through the bean container.

You can only do that while CDI is in the process of bootstrapping itself. Which means that Hibernate and CDI would have to be bootstrapped simultaneously.

It's not possible to register a new CDI bean after CDI has already started, since CDI validates all bean inter-dependencies during the startup phase, and if a bean is missing, it reports an error.

Currently this works because Hibernate starts before CDI, due to the whole problem with ClassTransformer, but that’s something we’re proposing to change because it causes problems.

Christian Beikov October 4, 2024 at 11:50 AM

Whatever we come up with for the JPA spec, we need a split in the bootstrap similar to what we have in Hibernate ORM. The first phase can’t use CDI and uses a temporary class loader to create the ClassTransformer whereas the second phase can fully leverage CDI.

The key thing to recognize is that there is no need to instantiate services like ConnectionProvider and MultiTenantConnectionProvider in the first bootstrap phase, so these contracts can safely be constructed through the bean container.

Gavin King October 4, 2024 at 11:28 AM

On the other hand, there is a well-defined way in CDI and Jakarta EE to allow components like MultiTenantConnectionProvider and CurrentTenantIdentifierResolver to have beans injected into them, without themselves needing to be beans.

This mechanism is also described in section 3.9 of the JPA spec.

That is the correct approach to use here.

Fixed

Details

Assignee

Reporter

Fix versions

Priority

Created July 27, 2022 at 9:23 AM
Updated December 3, 2024 at 9:49 AM
Resolved October 17, 2024 at 8:07 AM