Markus Jung created TOMEE-4661:
----------------------------------

             Summary: Register the Jakarta Persistence 3.2 CDI beans for 
persistence.xml-declared units
                 Key: TOMEE-4661
                 URL: https://issues.apache.org/jira/browse/TOMEE-4661
             Project: TomEE
          Issue Type: Bug
            Reporter: Markus Jung


TomEE does not register the CDI beans that the Jakarta EE 11 Platform 
specification requires for {{persistence.xml}}-declared persistence units. When 
an application injects {{EntityManagerFactory}}, {{EntityManager}}, or 
{{PersistenceUnitUtil}} with a qualifier such as {{@CtsEm2Qualifier}}, 
deployment fails with {{UnsatisfiedResolutionException}}.

This reproduces on Plume (EclipseLink) and on the webprofile distribution 
(OpenJPA) alike, so it is not a persistence provider defect.

Split out of TOMEE-4650, which now covers only the undeploy/double-close half.

h2. Required beans

Per the Jakarta EE 11 Platform specification, section "Jakarta Persistence & 
Jakarta Context and Dependency Injection (CDI) Integration" ({{CDI-JPA.adoc}}), 
the container must make available, for each persistence unit:
* {{EntityManagerFactory}} — scope {{ApplicationScoped}}, bean name = the 
persistence unit name
* {{EntityManager}} — scope given by the {{<scope>}} element, defaulting to 
{{jakarta.transaction.TransactionScoped}}
* {{CriteriaBuilder}}, {{PersistenceUnitUtil}}, {{Cache}}, {{SchemaManager}}, 
{{Metamodel}} — scope {{Dependent}}, each obtained by calling the matching 
getter on the {{EntityManagerFactory}} bean

All carry the qualifiers given by the {{<qualifier>}} elements of 
{{persistence.xml}}, or {{jakarta.enterprise.inject.Default}} if none is 
declared. None have interceptor bindings.

Supporting work: {{<qualifier>}} and {{<scope>}} must be added to the 
{{persistence.xml}} JAXB model 
({{org.apache.openejb.jee.jpa.unit.PersistenceUnit}}, hand-maintained, elements 
go after {{provider}} per {{persistence_3_2.xsd}}), carried through 
{{PersistenceUnitInfo}} and {{AppInfoBuilder}}.

h2. Steps to reproduce / TCK reference

{{ee.jakarta.tck.persistence.ee.cdi.ServletEMLookupTest}} — excluded in 
{{runner-webprofile/exclusions/persistence-servlet.txt}} in the 
apache/tomee-tck harness repo. Remove that line once fixed.

Note the TCK's {{persistence.xml}} uses the plain {{<qualifier>}} element, not 
the {{cdi:}}-namespaced extension-point form.

h2. Prior attempt and review findings

A first implementation was proposed in 
https://github.com/apache/tomee/pull/2847 and dropped from that PR after 
review. It is preserved on branch {{claude/tomee-4650-jpa-cdi-extension}}. 
Issues to address before it can land:

_Blocking_
* No {{getBeans()}} guard before registering {{@Default}} beans for unqualified 
units. Beans added via {{AfterBeanDiscovery.addBean()}} are ordinary enabled 
beans, not built-ins, so this produces an {{AmbiguousResolutionException}} 
against the common {{@Produces EntityManager}} pattern. Confirmed: it breaks 
{{ProducedExtendedEmTest}} and would break {{ResourceLocalCdiEmTest}}. 
{{ConcurrencyCDIExtension.registerDefaultBeanIfMissing}} is the model to follow.
* No app/webapp scoping: no dedup of qualifier sets and no filter on 
{{unitInfo.webappName}}, so duplicate {{@Default}} beans are registered for two 
unqualified units in one app, and in an EAR a webapp receives beans for its 
siblings' units. Compare {{ConcurrencyCDIExtension.isVisibleInCurrentApp}}.
* The annotation proxy violates the {{Annotation}} equals/hashCode contract 
({{equals}} ignores member values; {{hashCode}} is not 0 for a marker 
annotation), so a qualifier with members can select the wrong unit. Reuse 
{{ConcurrencyCDIExtension.annotationEquals}}/{{annotationHashCode}} rather than 
reimplementing.
* Qualifier validation stops at the {{@Qualifier}} check; it must also reject 
members lacking defaults and members lacking {{@Nonbinding}}, as 
{{ConcurrencyCDIExtension.validateAndCreateQualifiers}} does.

_Also_
* {{jakarta.persistence.qualifiers}} / {{jakarta.persistence.scope}} are not 
specification properties — they appear in the Platform spec's property table 
but are not declared in {{jakarta.persistence-api-3.2.0.jar}} and are absent 
from {{PersistenceConfiguration}}. Use an {{openejb.*}} prefix instead of 
minting names under {{jakarta.*}}.
* {{<scope>}} is not validated as an actual CDI scope, unlike {{<qualifier>}}.
* Use {{JndiConstants.PERSISTENCE_UNIT_NAMING_CONTEXT}} rather than a hardcoded 
prefix.
* The {{jakarta.transaction}}-absent fallback is unreachable (openejb-core 
depends on it unconditionally) and can only cause a silent scope change; drop 
it.
* The {{SchemaManager}} bean can only inject null as wired; fix or drop it.
* The {{EntityManager}} is handed out unwrapped by {{JtaEntityManager}}, 
bypassing TomEE's JTA integration.
* {{resolveEntityManagerScope}} never consults {{unitInfo.transactionType}}, so 
a RESOURCE\_LOCAL unit gets {{TransactionScoped}} and is unusable outside a JTA 
transaction. The Platform spec states the default unconditionally, with no 
RESOURCE\_LOCAL carve-out; this looks like a spec gap worth raising upstream 
rather than guessing.
* The {{@Dependent}} utility beans capture the current delegate at 
instantiation, so after {{ReloadableEntityManagerFactory.reload()}} they can be 
bound to a superseded EMF. Resolve through the EMF per call, or document the 
limitation.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to