mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 08:24:13 +00:00
Runtime compatibility with JPA 4.0.0-M1 and Hibernate ORM 8.0.0.Alpha1
Closes gh-35705
This commit is contained in:
+12
@@ -21,6 +21,7 @@ import java.util.List;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import jakarta.persistence.EntityManagerFactory;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.PersistenceConfiguration;
|
||||
import jakarta.persistence.PersistenceException;
|
||||
import jakarta.persistence.SharedCacheMode;
|
||||
@@ -287,6 +288,17 @@ public class LocalContainerEntityManagerFactoryBean extends AbstractEntityManage
|
||||
this.internalPersistenceUnitManager.setValidationMode(validationMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the JPA 4.0 default fetch type for all of this manager's persistence
|
||||
* units, overriding any value in {@code persistence.xml} if set.
|
||||
* <p><b>NOTE: Only applied if no external PersistenceUnitManager specified. Also,
|
||||
* this requires a JPA 4.0+ persistence provider and will be ignored otherwise.</b>
|
||||
* @since 7.0.4
|
||||
*/
|
||||
public void setDefaultToOneFetchType(FetchType defaultToOneFetchType) {
|
||||
this.internalPersistenceUnitManager.setDefaultToOneFetchType(defaultToOneFetchType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the JDBC DataSource that the JPA persistence provider is supposed
|
||||
* to use for accessing the database. This is an alternative to keeping the
|
||||
|
||||
+17
@@ -27,6 +27,7 @@ import java.util.Set;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.PersistenceConfiguration;
|
||||
import jakarta.persistence.PersistenceException;
|
||||
import jakarta.persistence.SharedCacheMode;
|
||||
@@ -123,6 +124,8 @@ public class DefaultPersistenceUnitManager
|
||||
|
||||
private @Nullable ValidationMode validationMode;
|
||||
|
||||
private @Nullable FetchType defaultToOneFetchType;
|
||||
|
||||
private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
|
||||
|
||||
private @Nullable DataSource defaultDataSource;
|
||||
@@ -291,6 +294,17 @@ public class DefaultPersistenceUnitManager
|
||||
this.validationMode = validationMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the JPA 4.0 default fetch type for all of this manager's persistence
|
||||
* units, overriding any value in {@code persistence.xml} if set.
|
||||
* <p>This setting only applies against a JPA 4.0+ persistence provider.
|
||||
* Otherwise, it will be ignored.
|
||||
* @since 7.0.4
|
||||
*/
|
||||
public void setDefaultToOneFetchType(FetchType defaultToOneFetchType) {
|
||||
this.defaultToOneFetchType = defaultToOneFetchType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the JDBC DataSources that the JPA persistence provider is supposed
|
||||
* to use for accessing the database, resolving data source names in
|
||||
@@ -475,6 +489,9 @@ public class DefaultPersistenceUnitManager
|
||||
if (this.validationMode != null) {
|
||||
pui.setValidationMode(this.validationMode);
|
||||
}
|
||||
if (this.defaultToOneFetchType != null) {
|
||||
pui.setDefaultToOneFetchType(this.defaultToOneFetchType);
|
||||
}
|
||||
|
||||
// Initialize persistence unit ClassLoader
|
||||
if (this.loadTimeWeaver != null) {
|
||||
|
||||
+11
@@ -23,6 +23,7 @@ import java.util.Properties;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.PersistenceUnitTransactionType;
|
||||
import jakarta.persistence.SharedCacheMode;
|
||||
import jakarta.persistence.ValidationMode;
|
||||
@@ -82,6 +83,8 @@ public class MutablePersistenceUnitInfo {
|
||||
|
||||
private ValidationMode validationMode = ValidationMode.AUTO;
|
||||
|
||||
private FetchType defaultToOneFetchType = FetchType.EAGER;
|
||||
|
||||
private Properties properties = new Properties();
|
||||
|
||||
private String persistenceXMLSchemaVersion = "3.2";
|
||||
@@ -213,6 +216,14 @@ public class MutablePersistenceUnitInfo {
|
||||
return this.validationMode;
|
||||
}
|
||||
|
||||
public void setDefaultToOneFetchType(FetchType defaultToOneFetchType) {
|
||||
this.defaultToOneFetchType = defaultToOneFetchType;
|
||||
}
|
||||
|
||||
public FetchType getDefaultToOneFetchType() {
|
||||
return this.defaultToOneFetchType;
|
||||
}
|
||||
|
||||
public void addProperty(String name, String value) {
|
||||
this.properties.setProperty(name, value);
|
||||
}
|
||||
|
||||
+9
@@ -26,6 +26,7 @@ import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.PersistenceUnitTransactionType;
|
||||
import jakarta.persistence.SharedCacheMode;
|
||||
import jakarta.persistence.ValidationMode;
|
||||
@@ -85,6 +86,8 @@ final class PersistenceUnitReader {
|
||||
|
||||
private static final String VALIDATION_MODE = "validation-mode";
|
||||
|
||||
private static final String DEFAULT_TO_ONE_FETCH_TYPE = "default-to-one-fetch-type";
|
||||
|
||||
private static final String PROPERTIES = "properties";
|
||||
|
||||
private static final String META_INF = "META-INF";
|
||||
@@ -251,6 +254,12 @@ final class PersistenceUnitReader {
|
||||
unitInfo.setValidationMode(ValidationMode.valueOf(validationMode));
|
||||
}
|
||||
|
||||
// set JPA 4.0 default fetch type
|
||||
String fetchType = DomUtils.getChildElementValueByTagName(persistenceUnit, DEFAULT_TO_ONE_FETCH_TYPE);
|
||||
if (StringUtils.hasText(fetchType)) {
|
||||
unitInfo.setDefaultToOneFetchType(FetchType.valueOf(fetchType));
|
||||
}
|
||||
|
||||
parseQualifiers(persistenceUnit, unitInfo);
|
||||
parseMappingFiles(persistenceUnit, unitInfo);
|
||||
parseJarFiles(persistenceUnit, unitInfo);
|
||||
|
||||
+23
-1
@@ -23,6 +23,7 @@ import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.PersistenceConfiguration;
|
||||
import jakarta.persistence.PersistenceUnitTransactionType;
|
||||
import jakarta.persistence.spi.ClassTransformer;
|
||||
@@ -207,6 +208,16 @@ public class SpringPersistenceUnitInfo extends MutablePersistenceUnitInfo {
|
||||
|
||||
setSharedCacheMode(config.sharedCacheMode());
|
||||
setValidationMode(config.validationMode());
|
||||
|
||||
// JPA 4.0 defaultToOneFetchType
|
||||
Method defaultToOneFetchType = ClassUtils.getMethodIfAvailable(config.getClass(), "defaultToOneFetchType");
|
||||
if (defaultToOneFetchType != null) {
|
||||
FetchType fetchType = (FetchType) ReflectionUtils.invokeMethod(defaultToOneFetchType, config);
|
||||
if (fetchType != null) {
|
||||
setDefaultToOneFetchType(fetchType);
|
||||
}
|
||||
}
|
||||
|
||||
getProperties().putAll(config.properties());
|
||||
|
||||
// Further relevant settings from HibernatePersistenceConfiguration on Hibernate 7.1+
|
||||
@@ -247,10 +258,21 @@ public class SpringPersistenceUnitInfo extends MutablePersistenceUnitInfo {
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Override
|
||||
public @Nullable Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
// Fast path for SmartPersistenceUnitInfo JTA check
|
||||
if (method.getName().equals("isConfiguredForJta")) {
|
||||
// Fast path for SmartPersistenceUnitInfo JTA check
|
||||
return (getTransactionType() == PersistenceUnitTransactionType.JTA);
|
||||
}
|
||||
else if (method.getName().equals("getAllManagedClassNames")) {
|
||||
// JPA 4.0 letting the container perform the scanning ->
|
||||
// with Spring, only makes sense with typical default persistence unit.
|
||||
if (excludeUnlistedClasses() && getMappingFileNames().isEmpty()) {
|
||||
List<String> mergedClassesAndPackages = new ArrayList<>(getManagedClassNames());
|
||||
mergedClassesAndPackages.addAll(getManagedPackages());
|
||||
return mergedClassesAndPackages;
|
||||
}
|
||||
throw new UnsupportedOperationException(
|
||||
"JPA 4.0 getAllManagedClassNames only supported with exclude-unlisted-classes and no orm.xml");
|
||||
}
|
||||
|
||||
// Regular methods to be delegated to SpringPersistenceUnitInfo
|
||||
Method targetMethod = SpringPersistenceUnitInfo.class.getMethod(method.getName(), method.getParameterTypes());
|
||||
|
||||
+40
-13
@@ -30,6 +30,7 @@ import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor;
|
||||
|
||||
import org.springframework.core.NativeDetector;
|
||||
import org.springframework.orm.jpa.persistenceunit.SmartPersistenceUnitInfo;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Spring-specific subclass of the standard {@link HibernatePersistenceProvider}
|
||||
@@ -51,19 +52,45 @@ class SpringHibernateJpaPersistenceProvider extends HibernatePersistenceProvider
|
||||
if (info instanceof SmartPersistenceUnitInfo smartInfo) {
|
||||
mergedClassesAndPackages.addAll(smartInfo.getManagedPackages());
|
||||
}
|
||||
return new EntityManagerFactoryBuilderImpl(
|
||||
new PersistenceUnitInfoDescriptor(info) {
|
||||
@Override
|
||||
public List<String> getManagedClassNames() {
|
||||
return mergedClassesAndPackages;
|
||||
}
|
||||
@Override
|
||||
public void pushClassTransformer(EnhancementContext enhancementContext) {
|
||||
if (!NativeDetector.inNativeImage()) {
|
||||
super.pushClassTransformer(enhancementContext);
|
||||
}
|
||||
}
|
||||
}, properties).build();
|
||||
|
||||
PersistenceUnitInfoDescriptor descriptor;
|
||||
if (!NativeDetector.inNativeImage()) {
|
||||
// No ClassTransformer adaptation necessary
|
||||
descriptor = new PersistenceUnitInfoDescriptor(info) {
|
||||
@Override
|
||||
public List<String> getManagedClassNames() {
|
||||
return mergedClassesAndPackages;
|
||||
}
|
||||
};
|
||||
}
|
||||
else if (ClassUtils.hasMethod(PersistenceUnitInfoDescriptor.class, "isClassTransformerRegistrationDisabled")) {
|
||||
// Hibernate 8.0: no pushClassTransformer override necessary
|
||||
descriptor = new PersistenceUnitInfoDescriptor(info) {
|
||||
@Override
|
||||
public List<String> getManagedClassNames() {
|
||||
return mergedClassesAndPackages;
|
||||
}
|
||||
// @Override on Hibernate 8.0
|
||||
public boolean isClassTransformerRegistrationDisabled() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
// Hibernate 7.x: pushClassTransformer no-op in native image
|
||||
descriptor = new PersistenceUnitInfoDescriptor(info) {
|
||||
@Override
|
||||
public List<String> getManagedClassNames() {
|
||||
return mergedClassesAndPackages;
|
||||
}
|
||||
@Override
|
||||
public void pushClassTransformer(EnhancementContext enhancementContext) {
|
||||
// no-op
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return new EntityManagerFactoryBuilderImpl(descriptor, properties).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
@@ -27,6 +27,7 @@ import jakarta.persistence.OptimisticLockException;
|
||||
import jakarta.persistence.PersistenceConfiguration;
|
||||
import jakarta.persistence.PersistenceException;
|
||||
import jakarta.persistence.PersistenceUnitTransactionType;
|
||||
import jakarta.persistence.spi.ClassTransformer;
|
||||
import jakarta.persistence.spi.PersistenceProvider;
|
||||
import jakarta.persistence.spi.PersistenceUnitInfo;
|
||||
import jakarta.persistence.spi.ProviderUtil;
|
||||
@@ -365,6 +366,16 @@ class LocalContainerEntityManagerFactoryBeanTests extends AbstractEntityManagerF
|
||||
public boolean generateSchema(String persistenceUnitName, Map map) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// JPA 4.0 method
|
||||
public boolean generateSchema(PersistenceConfiguration persistenceConfiguration) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// JPA 4.0 method
|
||||
public ClassTransformer getClassTransformer(PersistenceUnitInfo persistenceUnitInfo, Map<?,?> map) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+13
@@ -21,6 +21,7 @@ import java.util.Properties;
|
||||
|
||||
import jakarta.persistence.EntityManagerFactory;
|
||||
import jakarta.persistence.PersistenceConfiguration;
|
||||
import jakarta.persistence.spi.ClassTransformer;
|
||||
import jakarta.persistence.spi.PersistenceProvider;
|
||||
import jakarta.persistence.spi.PersistenceUnitInfo;
|
||||
import jakarta.persistence.spi.ProviderUtil;
|
||||
@@ -184,15 +185,27 @@ class LocalEntityManagerFactoryBeanTests extends AbstractEntityManagerFactoryBea
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// JPA 2.1 method
|
||||
@Override
|
||||
public void generateSchema(PersistenceUnitInfo persistenceUnitInfo, Map map) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// JPA 2.1 method
|
||||
@Override
|
||||
public boolean generateSchema(String persistenceUnitName, Map map) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// JPA 4.0 method
|
||||
public boolean generateSchema(PersistenceConfiguration persistenceConfiguration) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// JPA 4.0 method
|
||||
public ClassTransformer getClassTransformer(PersistenceUnitInfo persistenceUnitInfo, Map<?,?> map) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user