Skip to content

Commit 0d56cf6

Browse files
authored
Fixed persistence provider check in createEntityManagerFactory(PersistenceConfiguration) (#2280)
Added junit tests for checks, checkForProviderProperty(Map) made static. Signed-off-by: Tomáš Kraus <[email protected]>
1 parent 7828f91 commit 0d56cf6

File tree

4 files changed

+327
-18
lines changed

4 files changed

+327
-18
lines changed

foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/config/PersistenceUnitProperties.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,19 @@
8484
*/
8585
public final class PersistenceUnitProperties {
8686

87+
/**
88+
* The {@code jakarta.persistence.provider} property specifies the name
89+
* of a provider-specific implementation of {@link jakarta.persistence.spi.PersistenceProvider}.
90+
* This property overrides the value specified in the persistence.xml.
91+
* <p>
92+
* <b>Allowed Values:</b>
93+
* <ul>
94+
* <li>fully qualified name of the provider-specific implementation class
95+
* <li>{@link Class} instance of the provider-specific implementation class
96+
* </ul>
97+
*/
98+
public static final String PROVIDER = "jakarta.persistence.provider";
99+
87100
/**
88101
* The {@code jakarta.persistence.transactionType} property specifies the
89102
* transaction type for the persistence unit. This property overrides the

jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/jpa/PersistenceProvider.java

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,10 @@ public EntityManagerFactory createEntityManagerFactory(String emName, Map<?, ?>
192192
// Never call this method from this class because of stack frames removal.
193193
@Override
194194
public EntityManagerFactory createEntityManagerFactory(PersistenceConfiguration configuration) {
195+
// Check whether persistence provider is set and matches EclipseLink known classes
196+
if (!isProviderEclipseLink(configuration)) {
197+
return null;
198+
}
195199
JPAInitializer initializer = getInitializer(configuration.name(), configuration.properties());
196200
// Root URL from method caller
197201
StackWalker stackWalker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
@@ -316,29 +320,59 @@ public JPAInitializer getInitializer(String emName, Map m){
316320
return JavaSECMPInitializer.getJavaSECMPInitializer(classLoader);
317321
}
318322

323+
// Package visibility is required for jUnit
319324
/**
320-
* Need to check that the provider property is null or set for EclipseLink
325+
* The Persistence bootstrap class must locate all the persistence providers using the PersistenceProviderResolver
326+
* mechanism described in Section 9.3 and call createEntityManagerFactory on them in turn until an appropriate backing
327+
* provider returns an EntityManagerFactory instance. A provider may deem itself as appropriate for the persistence unit
328+
* if any of the following are true:
329+
* <p> * Its implementation class has been specified in the provider element for that persistence unit in the persistence.xml
330+
* file and has not been overridden by a different jakarta.persistence.provider property value included in the Map passed
331+
* to the createEntityManagerFactory method.
332+
* <p> * The jakarta.persistence.provider property was included in the Map passed to createEntityManagerFactory and the value
333+
* of the property is the provider’s implementation class.
334+
* <p> * No provider was specified for the persistence unit in either the persistence.xml or the property map.
335+
*
336+
* @since Jakarta Persistence 3.2
321337
*/
322-
public boolean checkForProviderProperty(Map properties){
323-
Object provider = properties.get("jakarta.persistence.provider");
324-
if (provider != null){
325-
//user has specified a provider make sure it is us or abort.
326-
if (provider instanceof Class){
327-
provider = ((Class)provider).getName();
328-
}
329-
try{
330-
if (!(EntityManagerFactoryProvider.class.getName().equals(provider) || PersistenceProvider.class.getName().equals(provider))){
331-
return false;
332-
//user has requested another provider so lets ignore this request.
333-
}
334-
}catch(ClassCastException e){
335-
return false;
336-
// not a recognized provider property value so must be another provider.
337-
}
338+
static boolean isProviderEclipseLink(PersistenceConfiguration configuration) {
339+
// Property jakarta.persistence.provider has higher priority, EclipseLink accepts it also as class.
340+
if (configuration.properties().containsKey(PersistenceUnitProperties.PROVIDER)) {
341+
return isProviderPropertyEclipseLink(configuration.properties().get(PersistenceUnitProperties.PROVIDER));
342+
}
343+
// Persistence unit provider configuration option
344+
if (configuration.provider() != null && !configuration.provider().isEmpty()) {
345+
return checkEclipseLinkProviderClassName(configuration.provider());
338346
}
339347
return true;
348+
}
340349

350+
/**
351+
* Need to check that the provider property is null or set for EclipseLink
352+
*/
353+
public static boolean checkForProviderProperty(Map<?, ?> properties) {
354+
return !properties.containsKey(PersistenceUnitProperties.PROVIDER)
355+
|| isProviderPropertyEclipseLink(properties.get(PersistenceUnitProperties.PROVIDER));
356+
}
357+
358+
// Check whether provided jakarta persistence provider property value matches any of known classes.
359+
// Supported property value types are String and Class<?>.
360+
private static boolean isProviderPropertyEclipseLink(Object providerProperty) {
361+
String providerClassName = (providerProperty instanceof String providerString) ? providerString : null;
362+
if (providerProperty instanceof Class<?> providerClass) {
363+
providerClassName = providerClass.getName();
364+
}
365+
return providerClassName != null && checkEclipseLinkProviderClassName(providerClassName);
366+
}
367+
368+
// Check whether provided jakarta persistence provider class name matches any of known classes:
369+
// * org.eclipse.persistence.jpa.PersistenceProvider
370+
// * org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider
371+
private static boolean checkEclipseLinkProviderClassName(String providerClassName) {
372+
return PersistenceProvider.class.getName().equals(providerClassName)
373+
|| EntityManagerFactoryProvider.class.getName().equals(providerClassName);
341374
}
375+
342376
/**
343377
* Called by the container when an EntityManagerFactory
344378
* is to be created.
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
/*
2+
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0,
7+
* or the Eclipse Distribution License v. 1.0 which is available at
8+
* http://www.eclipse.org/org/documents/edl-v10.php.
9+
*
10+
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
11+
*/
12+
package org.eclipse.persistence.jpa;
13+
14+
import java.util.Map;
15+
16+
import jakarta.persistence.EntityManagerFactory;
17+
import jakarta.persistence.PersistenceConfiguration;
18+
import jakarta.persistence.spi.PersistenceUnitInfo;
19+
import jakarta.persistence.spi.ProviderUtil;
20+
import org.eclipse.persistence.config.PersistenceUnitProperties;
21+
import org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider;
22+
import org.junit.jupiter.api.Test;
23+
24+
import static org.junit.jupiter.api.Assertions.assertTrue;
25+
import static org.junit.jupiter.api.Assertions.assertFalse;
26+
27+
public class PersistenceProviderTest {
28+
29+
@Test
30+
void testCheckForProviderPropertyWithoutProperty() {
31+
Map<String, Object> properties = Map.of();
32+
boolean result = PersistenceProvider.checkForProviderProperty(properties);
33+
assertTrue(result);
34+
}
35+
36+
@Test
37+
void testCheckForProviderPropertyWithProviderClass() {
38+
Map<String, Object> properties = Map.of(
39+
PersistenceUnitProperties.PROVIDER, PersistenceProvider.class
40+
);
41+
boolean result = PersistenceProvider.checkForProviderProperty(properties);
42+
assertTrue(result);
43+
}
44+
45+
@Test
46+
void testCheckForProviderPropertyWithProviderString() {
47+
Map<String, Object> properties = Map.of(
48+
PersistenceUnitProperties.PROVIDER, PersistenceProvider.class.getName()
49+
);
50+
boolean result = PersistenceProvider.checkForProviderProperty(properties);
51+
assertTrue(result);
52+
}
53+
54+
@Test
55+
void testCheckForProviderPropertyWithEMFProviderClass() {
56+
Map<String, Object> properties = Map.of(
57+
PersistenceUnitProperties.PROVIDER, EntityManagerFactoryProvider.class
58+
);
59+
boolean result = PersistenceProvider.checkForProviderProperty(properties);
60+
assertTrue(result);
61+
}
62+
63+
@Test
64+
void testCheckForProviderPropertyWithEMFProviderString() {
65+
Map<String, Object> properties = Map.of(
66+
PersistenceUnitProperties.PROVIDER, EntityManagerFactoryProvider.class.getName()
67+
);
68+
boolean result = PersistenceProvider.checkForProviderProperty(properties);
69+
assertTrue(result);
70+
}
71+
72+
@Test
73+
void testCheckForProviderPropertyWithUnsupportedClass() {
74+
Map<String, Object> properties = Map.of(
75+
PersistenceUnitProperties.PROVIDER, Unsupported.class
76+
);
77+
boolean result = PersistenceProvider.checkForProviderProperty(properties);
78+
assertFalse(result);
79+
}
80+
81+
@Test
82+
void testCheckForProviderPropertyWithUnsupportedString() {
83+
Map<String, Object> properties = Map.of(
84+
PersistenceUnitProperties.PROVIDER, Unsupported.class.getName()
85+
);
86+
boolean result = PersistenceProvider.checkForProviderProperty(properties);
87+
assertFalse(result);
88+
}
89+
90+
@Test
91+
void testIsProviderEclipseLinkWithoutProvider() {
92+
PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
93+
boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
94+
assertTrue(result);
95+
}
96+
97+
@Test
98+
void testIsProviderEclipseLinkWithProvider() {
99+
PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
100+
configuration.provider(PersistenceProvider.class.getName());
101+
boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
102+
assertTrue(result);
103+
}
104+
105+
@Test
106+
void testIsProviderEclipseLinkWithEMFProvider() {
107+
PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
108+
configuration.provider(EntityManagerFactoryProvider.class.getName());
109+
boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
110+
assertTrue(result);
111+
}
112+
113+
@Test
114+
void testIsProviderEclipseLinkWithUnsupportedProvider() {
115+
PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
116+
configuration.provider(Unsupported.class.getName());
117+
boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
118+
assertFalse(result);
119+
}
120+
121+
@Test
122+
void testIsProviderEclipseLinkWithProviderStringProperty() {
123+
Map<String, Object> properties = Map.of(
124+
PersistenceUnitProperties.PROVIDER, PersistenceProvider.class.getName()
125+
);
126+
PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
127+
configuration.properties(properties);
128+
boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
129+
assertTrue(result);
130+
}
131+
132+
@Test
133+
void testIsProviderEclipseLinkWithEMFProviderStringProperty() {
134+
Map<String, Object> properties = Map.of(
135+
PersistenceUnitProperties.PROVIDER, EntityManagerFactoryProvider.class.getName()
136+
);
137+
PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
138+
configuration.properties(properties);
139+
boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
140+
assertTrue(result);
141+
}
142+
143+
@Test
144+
void testIsProviderEclipseLinkWithUnsupportedProviderStringProperty() {
145+
Map<String, Object> properties = Map.of(
146+
PersistenceUnitProperties.PROVIDER, Unsupported.class.getName()
147+
);
148+
PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
149+
configuration.properties(properties);
150+
boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
151+
assertFalse(result);
152+
}
153+
154+
@Test
155+
void testIsProviderEclipseLinkWithProviderClassProperty() {
156+
Map<String, Object> properties = Map.of(
157+
PersistenceUnitProperties.PROVIDER, PersistenceProvider.class
158+
);
159+
PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
160+
configuration.properties(properties);
161+
boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
162+
assertTrue(result);
163+
}
164+
165+
@Test
166+
void testIsProviderEclipseLinkWithEMFProviderClassProperty() {
167+
Map<String, Object> properties = Map.of(
168+
PersistenceUnitProperties.PROVIDER, EntityManagerFactoryProvider.class
169+
);
170+
PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
171+
configuration.properties(properties);
172+
boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
173+
assertTrue(result);
174+
}
175+
176+
@Test
177+
void testIsProviderEclipseLinkWithUnsupportedProviderClassProperty() {
178+
Map<String, Object> properties = Map.of(
179+
PersistenceUnitProperties.PROVIDER, Unsupported.class
180+
);
181+
PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
182+
configuration.properties(properties);
183+
boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
184+
assertFalse(result);
185+
}
186+
187+
188+
@Test
189+
void testIsProviderEclipseLinkWithProviderStringPropertyOverride() {
190+
Map<String, Object> properties = Map.of(
191+
PersistenceUnitProperties.PROVIDER, PersistenceProvider.class.getName()
192+
);
193+
PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
194+
// Provider is set as unsupported, but supported property must override it
195+
configuration.provider(Unsupported.class.getName());
196+
configuration.properties(properties);
197+
boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
198+
assertTrue(result);
199+
}
200+
201+
@Test
202+
void testIsProviderEclipseLinkWithEMFProviderStringPropertyOverride() {
203+
Map<String, Object> properties = Map.of(
204+
PersistenceUnitProperties.PROVIDER, EntityManagerFactoryProvider.class.getName()
205+
);
206+
PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
207+
// Provider is set as unsupported, but supported property must override it
208+
configuration.provider(Unsupported.class.getName());
209+
configuration.properties(properties);
210+
boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
211+
assertTrue(result);
212+
}
213+
214+
@Test
215+
void testIsProviderEclipseLinkWithUnsupportedProviderStringPropertyOverride() {
216+
Map<String, Object> properties = Map.of(
217+
PersistenceUnitProperties.PROVIDER, Unsupported.class.getName()
218+
);
219+
PersistenceConfiguration configuration = new PersistenceConfiguration("Test");
220+
// Provider is set as supported, but unsupported property must override it
221+
configuration.provider(PersistenceProvider.class.getName());
222+
configuration.properties(properties);
223+
boolean result = PersistenceProvider.isProviderEclipseLink(configuration);
224+
assertFalse(result);
225+
}
226+
227+
// PersistenceProvider that shall fail the check
228+
private static final class Unsupported implements jakarta.persistence.spi.PersistenceProvider {
229+
230+
@Override
231+
public EntityManagerFactory createEntityManagerFactory(String emName, Map<?, ?> map) {
232+
return null;
233+
}
234+
235+
@Override
236+
public EntityManagerFactory createEntityManagerFactory(PersistenceConfiguration configuration) {
237+
return null;
238+
}
239+
240+
@Override
241+
public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map<?, ?> map) {
242+
return null;
243+
}
244+
245+
@Override
246+
public void generateSchema(PersistenceUnitInfo info, Map<?, ?> map) {
247+
248+
}
249+
250+
@Override
251+
public boolean generateSchema(String persistenceUnitName, Map<?, ?> map) {
252+
return false;
253+
}
254+
255+
@Override
256+
public ProviderUtil getProviderUtil() {
257+
return null;
258+
}
259+
260+
}
261+
262+
}

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1287,7 +1287,7 @@
12871287
<!-- see https://github.com/eclipse-ee4j/eclipselink-build-support -->
12881288
<groupId>org.eclipse.persistence</groupId>
12891289
<artifactId>eclipselink-testbuild-plugin</artifactId>
1290-
<version>1.1.0</version>
1290+
<version>1.1.1</version>
12911291
</plugin>
12921292
<plugin>
12931293
<groupId>org.carlspring.maven</groupId>

0 commit comments

Comments
 (0)