Skip to content

Commit

Permalink
Fixed persistence provider check in createEntityManagerFactory(Persis…
Browse files Browse the repository at this point in the history
…tenceConfiguration) (#2280)

Added junit tests for checks, checkForProviderProperty(Map) made static.

Signed-off-by: Tomáš Kraus <[email protected]>
  • Loading branch information
Tomas-Kraus authored Oct 21, 2024
1 parent 7828f91 commit 0d56cf6
Show file tree
Hide file tree
Showing 4 changed files with 327 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.
* <p>
* <b>Allowed Values:</b>
* <ul>
* <li>fully qualified name of the provider-specific implementation class
* <li>{@link Class} instance of the provider-specific implementation class
* </ul>
*/
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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:
* <p> * 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.
* <p> * 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.
* <p> * 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.
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String, Object> properties = Map.of();
boolean result = PersistenceProvider.checkForProviderProperty(properties);
assertTrue(result);
}

@Test
void testCheckForProviderPropertyWithProviderClass() {
Map<String, Object> properties = Map.of(
PersistenceUnitProperties.PROVIDER, PersistenceProvider.class
);
boolean result = PersistenceProvider.checkForProviderProperty(properties);
assertTrue(result);
}

@Test
void testCheckForProviderPropertyWithProviderString() {
Map<String, Object> properties = Map.of(
PersistenceUnitProperties.PROVIDER, PersistenceProvider.class.getName()
);
boolean result = PersistenceProvider.checkForProviderProperty(properties);
assertTrue(result);
}

@Test
void testCheckForProviderPropertyWithEMFProviderClass() {
Map<String, Object> properties = Map.of(
PersistenceUnitProperties.PROVIDER, EntityManagerFactoryProvider.class
);
boolean result = PersistenceProvider.checkForProviderProperty(properties);
assertTrue(result);
}

@Test
void testCheckForProviderPropertyWithEMFProviderString() {
Map<String, Object> properties = Map.of(
PersistenceUnitProperties.PROVIDER, EntityManagerFactoryProvider.class.getName()
);
boolean result = PersistenceProvider.checkForProviderProperty(properties);
assertTrue(result);
}

@Test
void testCheckForProviderPropertyWithUnsupportedClass() {
Map<String, Object> properties = Map.of(
PersistenceUnitProperties.PROVIDER, Unsupported.class
);
boolean result = PersistenceProvider.checkForProviderProperty(properties);
assertFalse(result);
}

@Test
void testCheckForProviderPropertyWithUnsupportedString() {
Map<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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;
}

}

}
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1287,7 +1287,7 @@
<!-- see https://github.com/eclipse-ee4j/eclipselink-build-support -->
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink-testbuild-plugin</artifactId>
<version>1.1.0</version>
<version>1.1.1</version>
</plugin>
<plugin>
<groupId>org.carlspring.maven</groupId>
Expand Down

0 comments on commit 0d56cf6

Please sign in to comment.