jakartaee-platform icon indicating copy to clipboard operation
jakartaee-platform copied to clipboard

Address duplicate generated EntityManagerFactory bean name deployment failures when `Injecting an Entity Manager Factory using CDI`

Open scottmarlow opened this issue 4 months ago • 4 comments

As per https://jakarta.ee/specifications/platform/11/jakarta-platform-spec-11.0#injecting-an-entity-manager-factory-using-cdi:

13.12.2. Injecting an Entity Manager Factory using CDI

A Jakarta EE container must feature built-in integration of Jakarta Persistence with the CDI bean manager, allowing injection of a container-managed entity manager using the annotation jakarta.inject.Inject.

For each persistence unit, the container must make available a bean with:

- bean type EntityManagerFactory,

- the qualifiers specified by qualifier XML elements in persistence.xml, or jakarta.enterprise.inject.Default, if no qualifiers are explicitly specified,

- scope jakarta.enterprise.context.ApplicationScoped,

- bean name given by the name of the persistence unit,

- no interceptor bindings,

- a bean implementation which satisfies the requirements of the Persistence specification for a container-managed entity manager factory.

Is your feature request related to a problem? Please describe.

EE implementations may create a single CDI BeanManager instance per application deployment to be used globally. EE implementations may also use other mappings such as an CDI BeanManager instance per deployment module which wouldn't get a duplicate bean error when there are duplicate persistence unit definitions.

For reference https://issues.redhat.com/browse/WFLY-19554 contains some background information about problems that can happen with existing application deployments that contain duplicate persistence unit definitions which are currently allowed by the Jakarta EE 11 specification.

In summary, think about an EAR deployment containing two subdeployments that each contain persistence definition:

<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
    <persistence-unit name="mainPu">
        <description>Persistence Unit.</description>
        <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
            <property name="hibernate.show_sql" value="false"/>
        </properties>
    </persistence-unit>
</persistence>

I think that some application servers may try to create two EntityManagerFactory CDI beans named mainPu (once per subdeployment that contains ^ persistence.xml). As is mentioned in https://issues.redhat.com/browse/WFLY-19554, I'm seeing a deployment failure [WELD-001414](https://issues.redhat.com/browse/WELD-1414): Bean name is ambiguous. Name mainPu resolves to beans: [Configurator Bean [interface jakarta.persistence.EntityManagerFactory, types: Object, EntityManagerFactory, AutoCloseable, qualifiers: @Any @Default], Configurator Bean [interface jakarta.persistence.EntityManagerFactory, types: Object, EntityManagerFactory, AutoCloseable, qualifiers: @Any @Default]]"}}}}

Describe the solution you'd like Clarify that the EntityManagerFactory bean may not be named when there are duplicate persistence unit definitions in an application.

Describe alternatives you've considered Specify a persistence unit hint that when used will ensure that the EntityManagerFactory CDI Bean name includes the containing module archive file name (e.g something like CDIPersistenceSchemaManagerTestCase.jar.pu2).

Additional context

Current test failures seen with WildFly:

[INFO] Running org.jboss.as.test.integration.jpa.packaging.PersistenceUnitWarPackagingTestCase
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 5.483 s <<< FAILURE! – in org.jboss.as.test.integration.jpa.packaging.PersistenceUnitWarPackagingTestCase
[ERROR] org.jboss.as.test.integration.jpa.packaging.PersistenceUnitWarPackagingTestCase – Time elapsed: 5.481 s <<< ERROR!
org.jboss.arquillian.container.spi.client.container.DeploymentException:
Cannot deploy scopedToEar.ear: {"WFLYCTL0062: Composite operation failed and was rolled back. Steps that failed:" => {"Operation step-1" => {"WFLYCTL0080: Failed services" => {"jboss.deployment.unit.\"scopedToEar.ear\".WeldStartService" => "Failed to start service
Caused by: org.jboss.weld.exceptions.DeploymentException: [WELD-001414](https://issues.redhat.com/browse/WELD-1414): Bean name is ambiguous. Name mainPu resolves to beans: [Configurator Bean [interface jakarta.persistence.EntityManagerFactory, types: Object, EntityManagerFactory, AutoCloseable, qualifiers: @Any @Default], Configurator Bean [interface jakarta.persistence.EntityManagerFactory, types: Object, EntityManagerFactory, AutoCloseable, qualifiers: @Any @Default]]"}}}}

[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 4.623 s <<< FAILURE! – in org.jboss.as.test.integration.jpa.packaging.PersistenceUnitPackagingTestCase
Caused by: org.jboss.weld.exceptions.DeploymentException: [WELD-001414](https://issues.redhat.com/browse/WELD-1414): Bean name is ambiguous. Name mainPu resolves to beans: [Configurator Bean [interface jakarta.persistence.EntityManagerFactory, types: Object, EntityManagerFactory, AutoCloseable, qualifiers: @Any @Default], Configurator Bean [interface

scottmarlow avatar Jul 30 '25 13:07 scottmarlow

Perhaps something like jakarta.persistence.entitymanagerfactory.make_beanname_unique to imply that the bean name should be generated to be unique but that doesn't work as how would the application developer know what the bean name will be?

WildFly has a built in fully scoped persistence unit name that is unique that includes the deployment archive name (plus the persistence unit name) that might be a good candidate for the bean name and applications can override the name via a hint. This would solve the uniqueness problem but not sure if this is right either as applications should be able to depend on a portable (to different EE implementation's) EntityManagerFactory bean name.

scottmarlow avatar Jul 30 '25 15:07 scottmarlow

I'm not sure of the solution but think I will rename this issue to just reflect the problem that needs to be solved.

scottmarlow avatar Jul 30 '25 15:07 scottmarlow

Some possible solutions:

  1. Do not name the EntityManagerFactory bean for persistence unit definitions that have the same persistence unit name as other persistence unit definitions in the same application deployment. In summary do not name EMF bean for duplicate persistence unit definitions. Portable applications should remove duplicate persistence unit definitions if they want the EntityManagerFactory bean to be named after the persistence unit.
  2. Allow vendor specific naming of the EntityManagerFactory bean that would be based on the persistence unit name + other application information.
  3. Deprecate support of duplicate persistence unit definitions in the Persistence spec and remove support for duplicate persistence unit definitions in a future Persistence spec release.

Are there any Jakarta EE 11 Platform requirements that prevent EE 11 implementations from using (1)?

scottmarlow avatar Aug 06 '25 16:08 scottmarlow

At the platform call today, we discussed this issue and below are some of the points from the call to aid in continued discussions in this issue:

  • Definitely need to add new tests in EE 12 to test scenarios that are not covered in the exist TCK tests.
  • May want to consider if we want to continue to support duplicate persistent units in EE 12 still or if we should change that.
  • If you are going to use duplicates, you will need to use a qualifiers in order to differentiate when doing CDI injection.
  • Is there a reason for the bean name to be defined in reality? Should it be changed to not be required?
  • A bean name is needed possibly for injecting into a Pages page for instance so if that is a requirement, then it would be good to have a test added for that.
  • BeanManager per application vs per module is where you can run into issues with the duplicate persistent unit names.
  • Beans need to be visible throughout the application per the CDI specification.
  • Instead of persistence unit name, it may make sense to use the CDI qualifier for the bean name possibly? That is what should be used by any of the injectors if not using the bean name. Or a combination of the persistence unit name and the qualifier.
  • Today when doing injecting using @PersistenceContext there is scoping added to specify which one of the duplicates to use, see https://jakarta.ee/specifications/persistence/3.2/jakarta-persistence-spec-3.2#a12459
  • Regardless, a Bean does require there to be a bean name.
  • Today this is scoped to the EntityManagerFactory only, but this conversation may also need to be considered for the other Persistence injected types (EntityManager, etc).
  • @Named was discussed, but in general it is mostly for allowing a way to work around things and not the general approach.

jhanders34 avatar Aug 26 '25 22:08 jhanders34