Skip to content

Commit d216236

Browse files
committed
Revise PersistenceUnitInfo management for compatibility with JPA 3.2/4.0
Closes gh-35622
1 parent b4dcb36 commit d216236

11 files changed

+125
-120
lines changed

spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@
3030
import jakarta.persistence.EntityTransaction;
3131
import jakarta.persistence.TransactionRequiredException;
3232
import jakarta.persistence.spi.PersistenceUnitInfo;
33-
import jakarta.persistence.spi.PersistenceUnitTransactionType;
3433
import org.apache.commons.logging.Log;
3534
import org.apache.commons.logging.LogFactory;
3635
import org.jspecify.annotations.Nullable;
3736

3837
import org.springframework.core.Ordered;
3938
import org.springframework.dao.DataAccessException;
4039
import org.springframework.dao.support.PersistenceExceptionTranslator;
40+
import org.springframework.orm.jpa.persistenceunit.SmartPersistenceUnitInfo;
4141
import org.springframework.transaction.support.ResourceHolderSynchronization;
4242
import org.springframework.transaction.support.TransactionSynchronizationManager;
4343
import org.springframework.util.Assert;
@@ -192,14 +192,13 @@ public static EntityManager createContainerManagedEntityManager(
192192
* transactions (according to the JPA 2.1 SynchronizationType rules)
193193
* @return the EntityManager proxy
194194
*/
195-
@SuppressWarnings("removal")
196195
private static EntityManager createProxy(EntityManager rawEntityManager,
197196
EntityManagerFactoryInfo emfInfo, boolean containerManaged, boolean synchronizedWithTransaction) {
198197

199198
Assert.notNull(emfInfo, "EntityManagerFactoryInfo must not be null");
200199
JpaDialect jpaDialect = emfInfo.getJpaDialect();
201200
PersistenceUnitInfo pui = emfInfo.getPersistenceUnitInfo();
202-
Boolean jta = (pui != null ? pui.getTransactionType() == PersistenceUnitTransactionType.JTA : null);
201+
Boolean jta = (pui instanceof SmartPersistenceUnitInfo spui ? spui.isConfiguredForJta() : null);
203202
return createProxy(rawEntityManager, emfInfo.getEntityManagerInterface(),
204203
emfInfo.getBeanClassLoader(), jpaDialect, jta, containerManaged, synchronizedWithTransaction);
205204
}

spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ public class DefaultPersistenceUnitManager
134134

135135
private final Set<String> persistenceUnitInfoNames = new HashSet<>();
136136

137-
private final Map<String, PersistenceUnitInfo> persistenceUnitInfos = new HashMap<>();
137+
private final Map<String, SpringPersistenceUnitInfo> persistenceUnitInfos = new HashMap<>();
138138

139139

140140
/**
@@ -620,26 +620,25 @@ private void applyManagedTypes(SpringPersistenceUnitInfo scannedUnit, Persistenc
620620

621621

622622
/**
623-
* Return the specified PersistenceUnitInfo from this manager's cache
624-
* of processed persistence units, keeping it in the cache (i.e. not
625-
* 'obtaining' it for use but rather just accessing it for post-processing).
623+
* Return the specified {@link MutablePersistenceUnitInfo} from this manager's cache
624+
* of processed persistence units, keeping it in the cache (i.e. not 'obtaining' it
625+
* for use but rather just accessing it for post-processing).
626626
* <p>This can be used in {@link #postProcessPersistenceUnitInfo} implementations,
627627
* detecting existing persistence units of the same name and potentially merging them.
628628
* @param persistenceUnitName the name of the desired persistence unit
629629
* @return the PersistenceUnitInfo in mutable form, or {@code null} if not available
630630
*/
631631
protected final @Nullable MutablePersistenceUnitInfo getPersistenceUnitInfo(String persistenceUnitName) {
632-
PersistenceUnitInfo pui = this.persistenceUnitInfos.get(persistenceUnitName);
633-
return (MutablePersistenceUnitInfo) pui;
632+
return this.persistenceUnitInfos.get(persistenceUnitName);
634633
}
635634

636635
/**
637-
* Hook method allowing subclasses to customize each PersistenceUnitInfo.
636+
* Hook method allowing subclasses to customize each {@link MutablePersistenceUnitInfo}.
638637
* <p>The default implementation delegates to all registered PersistenceUnitPostProcessors.
639638
* It is usually preferable to register further entity classes, jar files etc there
640639
* rather than in a subclass of this manager, to be able to reuse the post-processors.
641-
* @param pui the chosen PersistenceUnitInfo, as read from {@code persistence.xml}.
642-
* Passed in as MutablePersistenceUnitInfo.
640+
* @param pui the chosen persistence unit configuration, as read from
641+
* {@code persistence.xml}. Passed in as MutablePersistenceUnitInfo.
643642
* @see #setPersistenceUnitPostProcessors
644643
*/
645644
protected void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
@@ -674,14 +673,14 @@ public PersistenceUnitInfo obtainDefaultPersistenceUnitInfo() {
674673
if (this.persistenceUnitInfos.size() > 1 && this.defaultPersistenceUnitName != null) {
675674
return obtainPersistenceUnitInfo(this.defaultPersistenceUnitName);
676675
}
677-
PersistenceUnitInfo pui = this.persistenceUnitInfos.values().iterator().next();
676+
SpringPersistenceUnitInfo pui = this.persistenceUnitInfos.values().iterator().next();
678677
this.persistenceUnitInfos.clear();
679-
return pui;
678+
return pui.toSmartPersistenceUnitInfo();
680679
}
681680

682681
@Override
683682
public PersistenceUnitInfo obtainPersistenceUnitInfo(String persistenceUnitName) {
684-
PersistenceUnitInfo pui = this.persistenceUnitInfos.remove(persistenceUnitName);
683+
SpringPersistenceUnitInfo pui = this.persistenceUnitInfos.remove(persistenceUnitName);
685684
if (pui == null) {
686685
if (!this.persistenceUnitInfoNames.contains(persistenceUnitName)) {
687686
throw new IllegalArgumentException(
@@ -692,7 +691,7 @@ public PersistenceUnitInfo obtainPersistenceUnitInfo(String persistenceUnitName)
692691
"Persistence unit with name '" + persistenceUnitName + "' already obtained");
693692
}
694693
}
695-
return pui;
694+
return pui.toSmartPersistenceUnitInfo();
696695
}
697696

698697
}

spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java

Lines changed: 7 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,31 @@
2323

2424
import javax.sql.DataSource;
2525

26+
import jakarta.persistence.PersistenceUnitTransactionType;
2627
import jakarta.persistence.SharedCacheMode;
2728
import jakarta.persistence.ValidationMode;
28-
import jakarta.persistence.spi.ClassTransformer;
29-
import jakarta.persistence.spi.PersistenceUnitTransactionType;
3029
import org.jspecify.annotations.Nullable;
3130

3231
import org.springframework.util.Assert;
33-
import org.springframework.util.ClassUtils;
3432

3533
/**
36-
* Spring's base implementation of the JPA
34+
* Spring's mutable equivalent of the JPA
3735
* {@link jakarta.persistence.spi.PersistenceUnitInfo} interface,
3836
* used to bootstrap an {@code EntityManagerFactory} in a container.
3937
*
4038
* <p>This implementation is largely a JavaBean, offering mutators
4139
* for all standard {@code PersistenceUnitInfo} properties.
40+
* As of 7.0, it does <i>not</i> implement {@code PersistenceUnitInfo} but
41+
* rather serves as the state behind a runtime {@code PersistenceUnitInfo}
42+
* (for achieving compatibility between JPA 3.2 and 4.0 and for preventing
43+
* late mutation attempts through {@code PersistenceUnitInfo} downcasts).
4244
*
4345
* @author Rod Johnson
4446
* @author Juergen Hoeller
4547
* @author Costin Leau
4648
* @since 2.0
4749
*/
48-
@SuppressWarnings("removal")
49-
public class MutablePersistenceUnitInfo implements SmartPersistenceUnitInfo {
50+
public class MutablePersistenceUnitInfo {
5051

5152
private @Nullable String persistenceUnitName;
5253

@@ -89,7 +90,6 @@ public void setPersistenceUnitName(@Nullable String persistenceUnitName) {
8990
this.persistenceUnitName = persistenceUnitName;
9091
}
9192

92-
@Override
9393
public @Nullable String getPersistenceUnitName() {
9494
return this.persistenceUnitName;
9595
}
@@ -98,7 +98,6 @@ public void setPersistenceProviderClassName(@Nullable String persistenceProvider
9898
this.persistenceProviderClassName = persistenceProviderClassName;
9999
}
100100

101-
@Override
102101
public @Nullable String getPersistenceProviderClassName() {
103102
return this.persistenceProviderClassName;
104103
}
@@ -107,7 +106,6 @@ public void setScopeAnnotationName(@Nullable String scopeAnnotationName) {
107106
this.scopeAnnotationName = scopeAnnotationName;
108107
}
109108

110-
@Override
111109
public @Nullable String getScopeAnnotationName() {
112110
return this.scopeAnnotationName;
113111
}
@@ -116,7 +114,6 @@ public void addQualifierAnnotationName(String qualifierAnnotationName) {
116114
this.qualifierAnnotationNames.add(qualifierAnnotationName);
117115
}
118116

119-
@Override
120117
public List<String> getQualifierAnnotationNames() {
121118
return this.qualifierAnnotationNames;
122119
}
@@ -125,7 +122,6 @@ public void setTransactionType(PersistenceUnitTransactionType transactionType) {
125122
this.transactionType = transactionType;
126123
}
127124

128-
@Override
129125
public PersistenceUnitTransactionType getTransactionType() {
130126
if (this.transactionType != null) {
131127
return this.transactionType;
@@ -140,7 +136,6 @@ public void setJtaDataSource(@Nullable DataSource jtaDataSource) {
140136
this.jtaDataSource = jtaDataSource;
141137
}
142138

143-
@Override
144139
public @Nullable DataSource getJtaDataSource() {
145140
return this.jtaDataSource;
146141
}
@@ -149,7 +144,6 @@ public void setNonJtaDataSource(@Nullable DataSource nonJtaDataSource) {
149144
this.nonJtaDataSource = nonJtaDataSource;
150145
}
151146

152-
@Override
153147
public @Nullable DataSource getNonJtaDataSource() {
154148
return this.nonJtaDataSource;
155149
}
@@ -158,7 +152,6 @@ public void addMappingFileName(String mappingFileName) {
158152
this.mappingFileNames.add(mappingFileName);
159153
}
160154

161-
@Override
162155
public List<String> getMappingFileNames() {
163156
return this.mappingFileNames;
164157
}
@@ -167,7 +160,6 @@ public void addJarFileUrl(URL jarFileUrl) {
167160
this.jarFileUrls.add(jarFileUrl);
168161
}
169162

170-
@Override
171163
public List<URL> getJarFileUrls() {
172164
return this.jarFileUrls;
173165
}
@@ -176,7 +168,6 @@ public void setPersistenceUnitRootUrl(@Nullable URL persistenceUnitRootUrl) {
176168
this.persistenceUnitRootUrl = persistenceUnitRootUrl;
177169
}
178170

179-
@Override
180171
public @Nullable URL getPersistenceUnitRootUrl() {
181172
return this.persistenceUnitRootUrl;
182173
}
@@ -190,7 +181,6 @@ public void addManagedClassName(String managedClassName) {
190181
this.managedClassNames.add(managedClassName);
191182
}
192183

193-
@Override
194184
public List<String> getManagedClassNames() {
195185
return this.managedClassNames;
196186
}
@@ -208,7 +198,6 @@ public void addManagedPackage(String packageName) {
208198
this.managedPackages.add(packageName);
209199
}
210200

211-
@Override
212201
public List<String> getManagedPackages() {
213202
return this.managedPackages;
214203
}
@@ -217,7 +206,6 @@ public void setExcludeUnlistedClasses(boolean excludeUnlistedClasses) {
217206
this.excludeUnlistedClasses = excludeUnlistedClasses;
218207
}
219208

220-
@Override
221209
public boolean excludeUnlistedClasses() {
222210
return this.excludeUnlistedClasses;
223211
}
@@ -226,7 +214,6 @@ public void setSharedCacheMode(SharedCacheMode sharedCacheMode) {
226214
this.sharedCacheMode = sharedCacheMode;
227215
}
228216

229-
@Override
230217
public SharedCacheMode getSharedCacheMode() {
231218
return this.sharedCacheMode;
232219
}
@@ -235,7 +222,6 @@ public void setValidationMode(ValidationMode validationMode) {
235222
this.validationMode = validationMode;
236223
}
237224

238-
@Override
239225
public ValidationMode getValidationMode() {
240226
return this.validationMode;
241227
}
@@ -249,7 +235,6 @@ public void setProperties(Properties properties) {
249235
this.properties = properties;
250236
}
251237

252-
@Override
253238
public Properties getProperties() {
254239
return this.properties;
255240
}
@@ -258,12 +243,10 @@ public void setPersistenceXMLSchemaVersion(String persistenceXMLSchemaVersion) {
258243
this.persistenceXMLSchemaVersion = persistenceXMLSchemaVersion;
259244
}
260245

261-
@Override
262246
public String getPersistenceXMLSchemaVersion() {
263247
return this.persistenceXMLSchemaVersion;
264248
}
265249

266-
@Override
267250
public void setPersistenceProviderPackageName(@Nullable String persistenceProviderPackageName) {
268251
this.persistenceProviderPackageName = persistenceProviderPackageName;
269252
}
@@ -273,32 +256,6 @@ public void setPersistenceProviderPackageName(@Nullable String persistenceProvid
273256
}
274257

275258

276-
/**
277-
* This implementation returns the default ClassLoader.
278-
* @see org.springframework.util.ClassUtils#getDefaultClassLoader()
279-
*/
280-
@Override
281-
public @Nullable ClassLoader getClassLoader() {
282-
return ClassUtils.getDefaultClassLoader();
283-
}
284-
285-
/**
286-
* This implementation throws an UnsupportedOperationException.
287-
*/
288-
@Override
289-
public void addTransformer(ClassTransformer classTransformer) {
290-
throw new UnsupportedOperationException("addTransformer not supported");
291-
}
292-
293-
/**
294-
* This implementation throws an UnsupportedOperationException.
295-
*/
296-
@Override
297-
public ClassLoader getNewTempClassLoader() {
298-
throw new UnsupportedOperationException("getNewTempClassLoader not supported");
299-
}
300-
301-
302259
@Override
303260
public String toString() {
304261
return "PersistenceUnitInfo: name '" + this.persistenceUnitName +

spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceUnitPostProcessor.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
package org.springframework.orm.jpa.persistenceunit;
1818

1919
/**
20-
* Callback interface for post-processing a JPA PersistenceUnitInfo.
21-
* Implementations can be registered with a DefaultPersistenceUnitManager
22-
* or via a LocalContainerEntityManagerFactoryBean.
20+
* Callback interface for post-processing a {@link MutablePersistenceUnitInfo}
21+
* configuration that Spring prepares for JPA persistence unit bootstrapping.
22+
*
23+
* <p>Implementations can be registered with a {@link DefaultPersistenceUnitManager}
24+
* or via a {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean}.
2325
*
2426
* @author Juergen Hoeller
2527
* @since 2.0
@@ -29,10 +31,10 @@
2931
public interface PersistenceUnitPostProcessor {
3032

3133
/**
32-
* Post-process the given PersistenceUnitInfo, for example registering
33-
* further entity classes and jar files.
34-
* @param pui the chosen PersistenceUnitInfo, as read from {@code persistence.xml}.
35-
* Passed in as MutablePersistenceUnitInfo.
34+
* Post-process the given {@link MutablePersistenceUnitInfo},
35+
* for example registering further entity classes and jar files.
36+
* @param pui the chosen persistence unit configuration, as read from
37+
* {@code persistence.xml}. Passed in as MutablePersistenceUnitInfo.
3638
*/
3739
void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui);
3840

spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@
2626
import javax.xml.parsers.DocumentBuilderFactory;
2727
import javax.xml.parsers.ParserConfigurationException;
2828

29+
import jakarta.persistence.PersistenceUnitTransactionType;
2930
import jakarta.persistence.SharedCacheMode;
3031
import jakarta.persistence.ValidationMode;
31-
import jakarta.persistence.spi.PersistenceUnitTransactionType;
3232
import org.apache.commons.logging.Log;
3333
import org.apache.commons.logging.LogFactory;
3434
import org.jspecify.annotations.Nullable;
@@ -189,7 +189,6 @@ void parseDocument(Resource resource, Document document, List<SpringPersistenceU
189189
/**
190190
* Parse the unit info DOM element.
191191
*/
192-
@SuppressWarnings("removal")
193192
SpringPersistenceUnitInfo parsePersistenceUnitInfo(
194193
Element persistenceUnit, String version, @Nullable URL rootUrl) throws IOException {
195194

spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SmartPersistenceUnitInfo.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,13 @@ public interface SmartPersistenceUnitInfo extends PersistenceUnitInfo {
4747
*/
4848
void setPersistenceProviderPackageName(String persistenceProviderPackageName);
4949

50+
/**
51+
* Determine whether this persistence unit is configured for JTA transactions.
52+
* <p>This allows for a quick check without referring to the JPA transaction type enum
53+
* (primarily for achieving compatibility between JPA 3.2 and 4.0).
54+
* @since 7.0
55+
* @see jakarta.persistence.PersistenceUnitTransactionType#JTA
56+
*/
57+
boolean isConfiguredForJta();
58+
5059
}

0 commit comments

Comments
 (0)