From d1b6dd703da585d60d174885ab55b9e39d422c88 Mon Sep 17 00:00:00 2001 From: Scott Marlow Date: Wed, 20 Nov 2024 08:44:42 -0500 Subject: [PATCH 1/4] [WFLY-19973] @PersistenceContext properties attribute will not be processed Signed-off-by: Scott Marlow --- .../bootstrap/WeldJpaInjectionServices.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/weld/jpa/src/main/java/org/jboss/as/weld/services/bootstrap/WeldJpaInjectionServices.java b/weld/jpa/src/main/java/org/jboss/as/weld/services/bootstrap/WeldJpaInjectionServices.java index 70b1a09a7211..73e15c974062 100644 --- a/weld/jpa/src/main/java/org/jboss/as/weld/services/bootstrap/WeldJpaInjectionServices.java +++ b/weld/jpa/src/main/java/org/jboss/as/weld/services/bootstrap/WeldJpaInjectionServices.java @@ -11,6 +11,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.HashMap; +import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; @@ -18,6 +19,7 @@ import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManagerFactory; import jakarta.persistence.PersistenceContext; +import jakarta.persistence.PersistenceProperty; import jakarta.persistence.PersistenceUnit; import jakarta.transaction.TransactionManager; import jakarta.transaction.TransactionSynchronizationRegistry; @@ -71,7 +73,7 @@ public ResourceReferenceFactory registerPersistenceContextInjecti public EntityManager call() throws Exception { return new TransactionScopedEntityManager( scopedPuName, - new HashMap<>(), + getProperties(context), persistenceUnitService.getEntityManagerFactory(), context.synchronization(), deploymentUnit.getAttachment(JpaAttachments.TRANSACTION_SYNCHRONIZATION_REGISTRY), @@ -122,6 +124,15 @@ private String getScopedPUName(final DeploymentUnit deploymentUnit, final String return scopedPu.getScopedPersistenceUnitName(); } + private static Map getProperties(PersistenceContext context) { + HashMap map = new HashMap(); + for (PersistenceProperty property : context.properties()) { + map.put(property.name(), property.value()); + } + return map; + } + + private static class EntityManagerResourceReferenceFactory implements ResourceReferenceFactory { private final String scopedPuName; private final EntityManagerFactory entityManagerFactory; @@ -139,9 +150,10 @@ public EntityManagerResourceReferenceFactory(String scopedPuName, EntityManagerF @Override public ResourceReference createResource() { - final TransactionScopedEntityManager result = new TransactionScopedEntityManager(scopedPuName, new HashMap<>(), entityManagerFactory, context.synchronization(), transactionSynchronizationRegistry, transactionManager); + final TransactionScopedEntityManager result = new TransactionScopedEntityManager(scopedPuName, getProperties(context), entityManagerFactory, context.synchronization(), transactionSynchronizationRegistry, transactionManager); return new SimpleResourceReference(result); } + } private static class LazyFactory implements ResourceReferenceFactory { From 28405db4be11388ef42145580e5d722bdf6f84e5 Mon Sep 17 00:00:00 2001 From: Scott Marlow Date: Fri, 22 Nov 2024 18:35:56 -0500 Subject: [PATCH 2/4] [WFLY-19973] Add test and also handle properties that are later added to the TransactionScopedEntityManager Signed-off-by: Scott Marlow --- .../TransactionScopedEntityManager.java | 5 +++++ .../weld/jpa/scoping/CdiJpaInjectingBean.java | 17 ++++++++++++++++- .../scoping/WeldJpaInjectionScopeTestCase.java | 14 ++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/jpa/subsystem/src/main/java/org/jboss/as/jpa/container/TransactionScopedEntityManager.java b/jpa/subsystem/src/main/java/org/jboss/as/jpa/container/TransactionScopedEntityManager.java index 3c4e2bd0bdd0..f7d696aba8e6 100644 --- a/jpa/subsystem/src/main/java/org/jboss/as/jpa/container/TransactionScopedEntityManager.java +++ b/jpa/subsystem/src/main/java/org/jboss/as/jpa/container/TransactionScopedEntityManager.java @@ -198,6 +198,11 @@ protected boolean skipQueryDetach() { return skipQueryDetach.booleanValue(); } + @Override + public void setProperty(String propertyName, Object value) { + properties.put(propertyName, value); + super.setProperty(propertyName, value); + } /** diff --git a/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/weld/jpa/scoping/CdiJpaInjectingBean.java b/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/weld/jpa/scoping/CdiJpaInjectingBean.java index 0fb6020252a2..060360ca5377 100644 --- a/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/weld/jpa/scoping/CdiJpaInjectingBean.java +++ b/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/weld/jpa/scoping/CdiJpaInjectingBean.java @@ -7,10 +7,13 @@ import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; +import jakarta.persistence.PersistenceProperty; import jakarta.persistence.Query; + public class CdiJpaInjectingBean { - @PersistenceContext(unitName = "cdiPu") + + @PersistenceContext(unitName = "cdiPu", properties = { @PersistenceProperty(name = "CdiJpaInjectingBean", value = "true")}) EntityManager em; public Employee queryEmployeeName(int id) { @@ -19,5 +22,17 @@ public Employee queryEmployeeName(int id) { return (Employee) q.getSingleResult(); } + public String getInitialPropertyValue() { + return (String) em.getProperties().get("CdiJpaInjectingBean"); + } + + public void setAdditionalPropertyValue(String value) { + System.out.println("setAdditionalPropertyValue on em=" + em); + em.setProperty("CdiJpaInjectingBean.additional", value); + } + public String getAdditionalPropertyValue() { + System.out.println("getAdditionalPropertyValue on em=" + em); + return (String) em.getProperties().get("CdiJpaInjectingBean.additional"); + } } diff --git a/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/weld/jpa/scoping/WeldJpaInjectionScopeTestCase.java b/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/weld/jpa/scoping/WeldJpaInjectionScopeTestCase.java index d8a50ef27b63..1f39cb79cbdc 100644 --- a/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/weld/jpa/scoping/WeldJpaInjectionScopeTestCase.java +++ b/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/weld/jpa/scoping/WeldJpaInjectionScopeTestCase.java @@ -73,5 +73,19 @@ public void testOrmXmlDefinedEmployeeEntity() throws Exception { } Assert.fail("NoResultException should occur but didn't!"); } + + // [WFLY-19973] (Weld injected) @PersistenceContext (initial) properties attribute should be processed + @Test + public void testInitialPersistenceContextPropertiesAreSet() throws Exception { + Assert.assertEquals("true",bean.getInitialPropertyValue()); + } + + // [WFLY-19973] (Weld injected) @PersistenceContext (later set) properties attribute should be available + @Test + public void testEntityManagerPropertiesAreSaved() throws Exception { + bean.setAdditionalPropertyValue("WeldJpaInjectionScopeTestCase.testproperty"); + Assert.assertEquals("WeldJpaInjectionScopeTestCase.testproperty",bean.getAdditionalPropertyValue()); + } + } From d2c37cca609bcb4e027b893790830df702ece39f Mon Sep 17 00:00:00 2001 From: Scott Marlow Date: Mon, 25 Nov 2024 12:11:45 -0500 Subject: [PATCH 3/4] [WFLY-19973] Pass empty HashMap which may be modified by application code EntityManager.setProperty(String, Object) Signed-off-by: Scott Marlow --- .../jboss/as/jpa/processor/PersistenceUnitServiceHandler.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jpa/subsystem/src/main/java/org/jboss/as/jpa/processor/PersistenceUnitServiceHandler.java b/jpa/subsystem/src/main/java/org/jboss/as/jpa/processor/PersistenceUnitServiceHandler.java index 103d1496688c..3e5bb834c80d 100644 --- a/jpa/subsystem/src/main/java/org/jboss/as/jpa/processor/PersistenceUnitServiceHandler.java +++ b/jpa/subsystem/src/main/java/org/jboss/as/jpa/processor/PersistenceUnitServiceHandler.java @@ -12,7 +12,6 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -718,7 +717,7 @@ public void inject(final PersistenceUnitServiceImpl value) throws binderService.getManagedObjectInjector().inject(new ValueManagedReferenceFactory( new TransactionScopedEntityManager( pu.getScopedPersistenceUnitName(), - Collections.emptyMap(), + new HashMap(), // WFLY-19973: pass empty HashMap that can be modified by application code. value.getEntityManagerFactory(), SynchronizationType.SYNCHRONIZED, transactionSynchronizationRegistry, transactionManager))); } From 2a0a771c681fe1dddb63b6af275bf4557c70a5b2 Mon Sep 17 00:00:00 2001 From: Scott Marlow Date: Mon, 25 Nov 2024 14:04:39 -0500 Subject: [PATCH 4/4] [WFLY-19973] Always pass HashMap into TransactionScopedEntityManager constructor Signed-off-by: Scott Marlow --- .../jboss/as/jpa/processor/JPAAnnotationProcessor.java | 5 +---- .../weld/jpa/scoping/CdiJpaInjectingBean.java | 10 ++++++++-- .../jpa/scoping/WeldJpaInjectionScopeTestCase.java | 6 ++++++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/jpa/subsystem/src/main/java/org/jboss/as/jpa/processor/JPAAnnotationProcessor.java b/jpa/subsystem/src/main/java/org/jboss/as/jpa/processor/JPAAnnotationProcessor.java index 79f3a5da7ebc..be0e572d3c85 100644 --- a/jpa/subsystem/src/main/java/org/jboss/as/jpa/processor/JPAAnnotationProcessor.java +++ b/jpa/subsystem/src/main/java/org/jboss/as/jpa/processor/JPAAnnotationProcessor.java @@ -292,16 +292,13 @@ private InjectionSource getBindingSource(final DeploymentUnit deploymentUnit, fi (stType == null || SynchronizationType.SYNCHRONIZED.name().equals(stType.asString()))? SynchronizationType.SYNCHRONIZED: SynchronizationType.UNSYNCHRONIZED; - Map properties; + final Map properties = new HashMap<>(); AnnotationValue value = annotation.value("properties"); AnnotationInstance[] props = value != null ? value.asNestedArray() : null; if (props != null) { - properties = new HashMap<>(); for (int source = 0; source < props.length; source++) { properties.put(props[source].value("name").asString(), props[source].value("value").asString()); } - } else { - properties = null; } // get deployment settings from top level du (jboss-all.xml is only parsed at the top level). final JPADeploymentSettings jpaDeploymentSettings = DeploymentUtils.getTopDeploymentUnit(deploymentUnit).getAttachment(JpaAttachments.DEPLOYMENT_SETTINGS_KEY); diff --git a/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/weld/jpa/scoping/CdiJpaInjectingBean.java b/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/weld/jpa/scoping/CdiJpaInjectingBean.java index 060360ca5377..84c3aeed2129 100644 --- a/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/weld/jpa/scoping/CdiJpaInjectingBean.java +++ b/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/weld/jpa/scoping/CdiJpaInjectingBean.java @@ -16,6 +16,9 @@ public class CdiJpaInjectingBean { @PersistenceContext(unitName = "cdiPu", properties = { @PersistenceProperty(name = "CdiJpaInjectingBean", value = "true")}) EntityManager em; + @PersistenceContext(unitName = "cdiPu") + EntityManager emEmptyProperties; + public Employee queryEmployeeName(int id) { Query q = em.createQuery("SELECT e FROM Employee e where e.id=:employeeId"); q.setParameter("employeeId", id); @@ -27,12 +30,15 @@ public String getInitialPropertyValue() { } public void setAdditionalPropertyValue(String value) { - System.out.println("setAdditionalPropertyValue on em=" + em); em.setProperty("CdiJpaInjectingBean.additional", value); } public String getAdditionalPropertyValue() { - System.out.println("getAdditionalPropertyValue on em=" + em); return (String) em.getProperties().get("CdiJpaInjectingBean.additional"); } + + public String addPropertyToEmptyPropertyMap(String value) { + emEmptyProperties.setProperty("CdiJpaInjectingBean.addToEmptyPropertyMap", value); + return (String) emEmptyProperties.getProperties().get("CdiJpaInjectingBean.addToEmptyPropertyMap"); + } } diff --git a/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/weld/jpa/scoping/WeldJpaInjectionScopeTestCase.java b/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/weld/jpa/scoping/WeldJpaInjectionScopeTestCase.java index 1f39cb79cbdc..16e773e7c101 100644 --- a/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/weld/jpa/scoping/WeldJpaInjectionScopeTestCase.java +++ b/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/weld/jpa/scoping/WeldJpaInjectionScopeTestCase.java @@ -87,5 +87,11 @@ public void testEntityManagerPropertiesAreSaved() throws Exception { Assert.assertEquals("WeldJpaInjectionScopeTestCase.testproperty",bean.getAdditionalPropertyValue()); } + // [WFLY-19973] (Weld injected) @PersistenceContext (later set) ensure that property can be added to empty property map + @Test + public void testEntityManagerPropertiesEmptyCase() throws Exception { + Assert.assertEquals("AddedToEmptyHashMap", bean.addPropertyToEmptyPropertyMap("AddedToEmptyHashMap")); + } + }