Skip to content

Better detection of when a persistence unit is needed and better reporting of when a non-existing PU is referenced #51198

@yrodiere

Description

@yrodiere

Description

Whether a persistence unit (PU) will actually exist is not a trivial question.

It will depend on whether both Hibernate ORM and Hibernate Reactive are in the classpath.
It will depend on configuration (is that PU referenced in application.properties), but not always (the default PU might be created even without any configuration).
It will depend on the nature (blocking or reactive) of the PU's datasource (see #51159), but not always (some multitenancy setups don't involve a build-time datasource).

We've been trying to throw exceptions during the build when a PU cannot be created, because just not creating it would leave users with a rather confusing exception about the relevant CDI beans (e.g. Session) simply not being there.
But in some setups that's actually counter-productive because the PU is not used anyway (see #51159).

Relatedly, we've had some conversation with @radcortez (#51105) regarding how other extensions derive the need for a client from the mere existence in the application of an injection point involving that client.

Let's try to improve the situation:

  1. Better discover whether an app requires a given persistence unit -- not just from configuration
  2. Better detect cases when a non-existing PU is actually used, still providing a clear, actionable error message.

Implementation ideas

Taking the above into account, I'd like to suggest the following:

  1. We formalize the concept of "persistence unit X is requested in the app", sourcing the information from:
    a. Configuration: if a PU is explicitly configured, it's requested. We may not know if it's requested in blocking or reactive form, however.
    b. CDI injection point: any injection point whose component is provided by the Hibernate ORM/Reactive extensions should be considered a request for the corresponding PU: SessionFactory, Session, Mutiny.SessionFactory, Mutiny.Session, and many more. In some cases we may know if it's requested in blocking or reactive form, but not all of them (e.g. Metamodel could make sense for blocking as well as reactive).
    c. Panache: the presence of a Panache entity assigned to a given PU is considered a request for the corresponding PU. In that case we know if it's requested as reactive or blocking -- at least in Panache 1.
  2. We take that information into account at build time to come up with a list of PUs we will try to add to the app.
  3. When we cannot add a PU to the app (e.g. because the PU's datasource is unconfigured), we will consult the list of PU requests, and act one of two ways depending on that:
    a. If the PU is for sure requested in the form we're currently handling (blocking or reactive), we will fail at build time as we do today.
    b. Otherwise (this implies the PU is not injected nor used in Panache), we will create "fake" CDI beans for the PU, which are always inactive, so that any dynamic use at runtime will trigger an exception clearly explaining why the PU is not around.

I think this strikes a reasonable balance between convenience for users and complexity for us. Though I can't say this is a very-high priority task, of course :)

Thoughts, opinions?

cc @radcortez @FroMage @lucamolteni

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions