diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/config/PersistenceUnitProperties.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/config/PersistenceUnitProperties.java
index ce9d7cdeb23..4e92eff95cc 100644
--- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/config/PersistenceUnitProperties.java
+++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/config/PersistenceUnitProperties.java
@@ -84,6 +84,19 @@
*/
public final class PersistenceUnitProperties {
+ /**
+ * The {@code jakarta.persistence.provider} property specifies the name
+ * of a provider-specific implementation of {@link jakarta.persistence.spi.PersistenceProvider}.
+ * This property overrides the value specified in the persistence.xml.
+ *
+ * Allowed Values:
+ *
+ * - fully qualified name of the provider-specific implementation class
+ *
- {@link Class} instance of the provider-specific implementation class
+ *
+ */
+ public static final String PROVIDER = "jakarta.persistence.provider";
+
/**
* The {@code jakarta.persistence.transactionType} property specifies the
* transaction type for the persistence unit. This property overrides the
diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/jpa/PersistenceProvider.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/jpa/PersistenceProvider.java
index ba56e7193d8..f7acc3b973e 100644
--- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/jpa/PersistenceProvider.java
+++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/jpa/PersistenceProvider.java
@@ -192,6 +192,10 @@ public EntityManagerFactory createEntityManagerFactory(String emName, Map, ?>
// Never call this method from this class because of stack frames removal.
@Override
public EntityManagerFactory createEntityManagerFactory(PersistenceConfiguration configuration) {
+ // Check whether persistence provider is set and matches EclipseLink known classes
+ if (!isProviderEclipseLink(configuration)) {
+ return null;
+ }
JPAInitializer initializer = getInitializer(configuration.name(), configuration.properties());
// Root URL from method caller
StackWalker stackWalker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
@@ -316,29 +320,59 @@ public JPAInitializer getInitializer(String emName, Map m){
return JavaSECMPInitializer.getJavaSECMPInitializer(classLoader);
}
+ // Package visibility is required for jUnit
/**
- * Need to check that the provider property is null or set for EclipseLink
+ * The Persistence bootstrap class must locate all the persistence providers using the PersistenceProviderResolver
+ * mechanism described in Section 9.3 and call createEntityManagerFactory on them in turn until an appropriate backing
+ * provider returns an EntityManagerFactory instance. A provider may deem itself as appropriate for the persistence unit
+ * if any of the following are true:
+ * * Its implementation class has been specified in the provider element for that persistence unit in the persistence.xml
+ * file and has not been overridden by a different jakarta.persistence.provider property value included in the Map passed
+ * to the createEntityManagerFactory method.
+ *
* The jakarta.persistence.provider property was included in the Map passed to createEntityManagerFactory and the value
+ * of the property is the provider’s implementation class.
+ *
* No provider was specified for the persistence unit in either the persistence.xml or the property map.
+ *
+ * @since Jakarta Persistence 3.2
*/
- public boolean checkForProviderProperty(Map properties){
- Object provider = properties.get("jakarta.persistence.provider");
- if (provider != null){
- //user has specified a provider make sure it is us or abort.
- if (provider instanceof Class){
- provider = ((Class)provider).getName();
- }
- try{
- if (!(EntityManagerFactoryProvider.class.getName().equals(provider) || PersistenceProvider.class.getName().equals(provider))){
- return false;
- //user has requested another provider so lets ignore this request.
- }
- }catch(ClassCastException e){
- return false;
- // not a recognized provider property value so must be another provider.
- }
+ static boolean isProviderEclipseLink(PersistenceConfiguration configuration) {
+ // Property jakarta.persistence.provider has higher priority, EclipseLink accepts it also as class.
+ if (configuration.properties().containsKey(PersistenceUnitProperties.PROVIDER)) {
+ return isProviderPropertyEclipseLink(configuration.properties().get(PersistenceUnitProperties.PROVIDER));
+ }
+ // Persistence unit provider configuration option
+ if (configuration.provider() != null && !configuration.provider().isEmpty()) {
+ return checkEclipseLinkProviderClassName(configuration.provider());
}
return true;
+ }
+ /**
+ * Need to check that the provider property is null or set for EclipseLink
+ */
+ public static boolean checkForProviderProperty(Map, ?> properties) {
+ return !properties.containsKey(PersistenceUnitProperties.PROVIDER)
+ || isProviderPropertyEclipseLink(properties.get(PersistenceUnitProperties.PROVIDER));
+ }
+
+ // Check whether provided jakarta persistence provider property value matches any of known classes.
+ // Supported property value types are String and Class>.
+ private static boolean isProviderPropertyEclipseLink(Object providerProperty) {
+ String providerClassName = (providerProperty instanceof String providerString) ? providerString : null;
+ if (providerProperty instanceof Class> providerClass) {
+ providerClassName = providerClass.getName();
+ }
+ return providerClassName != null && checkEclipseLinkProviderClassName(providerClassName);
+ }
+
+ // Check whether provided jakarta persistence provider class name matches any of known classes:
+ // * org.eclipse.persistence.jpa.PersistenceProvider
+ // * org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider
+ private static boolean checkEclipseLinkProviderClassName(String providerClassName) {
+ return PersistenceProvider.class.getName().equals(providerClassName)
+ || EntityManagerFactoryProvider.class.getName().equals(providerClassName);
}
+
/**
* Called by the container when an EntityManagerFactory
* is to be created.
diff --git a/jpa/org.eclipse.persistence.jpa/src/test/java/org/eclipse/persistence/jpa/PersistenceProviderTest.java b/jpa/org.eclipse.persistence.jpa/src/test/java/org/eclipse/persistence/jpa/PersistenceProviderTest.java
new file mode 100644
index 00000000000..c1d7e9f3de1
--- /dev/null
+++ b/jpa/org.eclipse.persistence.jpa/src/test/java/org/eclipse/persistence/jpa/PersistenceProviderTest.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+package org.eclipse.persistence.jpa;
+
+import java.util.Map;
+
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.PersistenceConfiguration;
+import jakarta.persistence.spi.PersistenceUnitInfo;
+import jakarta.persistence.spi.ProviderUtil;
+import org.eclipse.persistence.config.PersistenceUnitProperties;
+import org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+public class PersistenceProviderTest {
+
+ @Test
+ void testCheckForProviderPropertyWithoutProperty() {
+ Map properties = Map.of();
+ boolean result = PersistenceProvider.checkForProviderProperty(properties);
+ assertTrue(result);
+ }
+
+ @Test
+ void testCheckForProviderPropertyWithProviderClass() {
+ Map properties = Map.of(
+ PersistenceUnitProperties.PROVIDER, PersistenceProvider.class
+ );
+ boolean result = PersistenceProvider.checkForProviderProperty(properties);
+ assertTrue(result);
+ }
+
+ @Test
+ void testCheckForProviderPropertyWithProviderString() {
+ Map properties = Map.of(
+ PersistenceUnitProperties.PROVIDER, PersistenceProvider.class.getName()
+ );
+ boolean result = PersistenceProvider.checkForProviderProperty(properties);
+ assertTrue(result);
+ }
+
+ @Test
+ void testCheckForProviderPropertyWithEMFProviderClass() {
+ Map properties = Map.of(
+ PersistenceUnitProperties.PROVIDER, EntityManagerFactoryProvider.class
+ );
+ boolean result = PersistenceProvider.checkForProviderProperty(properties);
+ assertTrue(result);
+ }
+
+ @Test
+ void testCheckForProviderPropertyWithEMFProviderString() {
+ Map properties = Map.of(
+ PersistenceUnitProperties.PROVIDER, EntityManagerFactoryProvider.class.getName()
+ );
+ boolean result = PersistenceProvider.checkForProviderProperty(properties);
+ assertTrue(result);
+ }
+
+ @Test
+ void testCheckForProviderPropertyWithUnsupportedClass() {
+ Map properties = Map.of(
+ PersistenceUnitProperties.PROVIDER, Unsupported.class
+ );
+ boolean result = PersistenceProvider.checkForProviderProperty(properties);
+ assertFalse(result);
+ }
+
+ @Test
+ void testCheckForProviderPropertyWithUnsupportedString() {
+ Map properties = Map.of(
+ PersistenceUnitProperties.PROVIDER, Unsupported.class.getName()
+ );
+ boolean result = PersistenceProvider.checkForProviderProperty(properties);
+ assertFalse(result);
+ }
+
+ @Test
+ void testIsProviderEclipseLinkWithoutProvider() {
+ PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
+ boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
+ assertTrue(result);
+ }
+
+ @Test
+ void testIsProviderEclipseLinkWithProvider() {
+ PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
+ configuration.provider(PersistenceProvider.class.getName());
+ boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
+ assertTrue(result);
+ }
+
+ @Test
+ void testIsProviderEclipseLinkWithEMFProvider() {
+ PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
+ configuration.provider(EntityManagerFactoryProvider.class.getName());
+ boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
+ assertTrue(result);
+ }
+
+ @Test
+ void testIsProviderEclipseLinkWithUnsupportedProvider() {
+ PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
+ configuration.provider(Unsupported.class.getName());
+ boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
+ assertFalse(result);
+ }
+
+ @Test
+ void testIsProviderEclipseLinkWithProviderStringProperty() {
+ Map properties = Map.of(
+ PersistenceUnitProperties.PROVIDER, PersistenceProvider.class.getName()
+ );
+ PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
+ configuration.properties(properties);
+ boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
+ assertTrue(result);
+ }
+
+ @Test
+ void testIsProviderEclipseLinkWithEMFProviderStringProperty() {
+ Map properties = Map.of(
+ PersistenceUnitProperties.PROVIDER, EntityManagerFactoryProvider.class.getName()
+ );
+ PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
+ configuration.properties(properties);
+ boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
+ assertTrue(result);
+ }
+
+ @Test
+ void testIsProviderEclipseLinkWithUnsupportedProviderStringProperty() {
+ Map properties = Map.of(
+ PersistenceUnitProperties.PROVIDER, Unsupported.class.getName()
+ );
+ PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
+ configuration.properties(properties);
+ boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
+ assertFalse(result);
+ }
+
+ @Test
+ void testIsProviderEclipseLinkWithProviderClassProperty() {
+ Map properties = Map.of(
+ PersistenceUnitProperties.PROVIDER, PersistenceProvider.class
+ );
+ PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
+ configuration.properties(properties);
+ boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
+ assertTrue(result);
+ }
+
+ @Test
+ void testIsProviderEclipseLinkWithEMFProviderClassProperty() {
+ Map properties = Map.of(
+ PersistenceUnitProperties.PROVIDER, EntityManagerFactoryProvider.class
+ );
+ PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
+ configuration.properties(properties);
+ boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
+ assertTrue(result);
+ }
+
+ @Test
+ void testIsProviderEclipseLinkWithUnsupportedProviderClassProperty() {
+ Map properties = Map.of(
+ PersistenceUnitProperties.PROVIDER, Unsupported.class
+ );
+ PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
+ configuration.properties(properties);
+ boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
+ assertFalse(result);
+ }
+
+
+ @Test
+ void testIsProviderEclipseLinkWithProviderStringPropertyOverride() {
+ Map properties = Map.of(
+ PersistenceUnitProperties.PROVIDER, PersistenceProvider.class.getName()
+ );
+ PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
+ // Provider is set as unsupported, but supported property must override it
+ configuration.provider(Unsupported.class.getName());
+ configuration.properties(properties);
+ boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
+ assertTrue(result);
+ }
+
+ @Test
+ void testIsProviderEclipseLinkWithEMFProviderStringPropertyOverride() {
+ Map properties = Map.of(
+ PersistenceUnitProperties.PROVIDER, EntityManagerFactoryProvider.class.getName()
+ );
+ PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
+ // Provider is set as unsupported, but supported property must override it
+ configuration.provider(Unsupported.class.getName());
+ configuration.properties(properties);
+ boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
+ assertTrue(result);
+ }
+
+ @Test
+ void testIsProviderEclipseLinkWithUnsupportedProviderStringPropertyOverride() {
+ Map properties = Map.of(
+ PersistenceUnitProperties.PROVIDER, Unsupported.class.getName()
+ );
+ PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
+ // Provider is set as supported, but unsupported property must override it
+ configuration.provider(PersistenceProvider.class.getName());
+ configuration.properties(properties);
+ boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
+ assertFalse(result);
+ }
+
+ // PersistenceProvider that shall fail the check
+ private static final class Unsupported implements jakarta.persistence.spi.PersistenceProvider {
+
+ @Override
+ public EntityManagerFactory createEntityManagerFactory(String emName, Map, ?> map) {
+ return null;
+ }
+
+ @Override
+ public EntityManagerFactory createEntityManagerFactory(PersistenceConfiguration configuration) {
+ return null;
+ }
+
+ @Override
+ public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map, ?> map) {
+ return null;
+ }
+
+ @Override
+ public void generateSchema(PersistenceUnitInfo info, Map, ?> map) {
+
+ }
+
+ @Override
+ public boolean generateSchema(String persistenceUnitName, Map, ?> map) {
+ return false;
+ }
+
+ @Override
+ public ProviderUtil getProviderUtil() {
+ return null;
+ }
+
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index eeb3deb100f..558dda9c5f4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1287,7 +1287,7 @@
org.eclipse.persistence
eclipselink-testbuild-plugin
- 1.1.0
+ 1.1.1
org.carlspring.maven