mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-27 09:39:04 +00:00
Add setPackagesToScan to LocalEntityManagerFactoryBean (and make setDataSource work)
Includes fix for consistent PersistenceException in case of no unit found for name. Includes proper tests for Local(Container)EntityManagerFactoryBean with scan setup. Closes gh-36270 Closes gh-36271
This commit is contained in:
-3
@@ -86,14 +86,11 @@ import org.springframework.util.StringUtils;
|
||||
* @author Juergen Hoeller
|
||||
* @author Rod Johnson
|
||||
* @since 2.0
|
||||
* @see #setPersistenceXmlLocation
|
||||
* @see #setJpaProperties
|
||||
* @see #setJpaVendorAdapter
|
||||
* @see #setLoadTimeWeaver
|
||||
* @see #setDataSource
|
||||
* @see EntityManagerFactoryInfo
|
||||
* @see LocalEntityManagerFactoryBean
|
||||
* @see org.springframework.orm.jpa.support.SharedEntityManagerBean
|
||||
* @see jakarta.persistence.spi.PersistenceProvider#createContainerEntityManagerFactory
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
|
||||
+72
-6
@@ -16,6 +16,9 @@
|
||||
|
||||
package org.springframework.orm.jpa;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import jakarta.persistence.EntityManagerFactory;
|
||||
@@ -25,8 +28,16 @@ import jakarta.persistence.PersistenceException;
|
||||
import jakarta.persistence.spi.PersistenceProvider;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
import org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager;
|
||||
import org.springframework.orm.jpa.persistenceunit.PersistenceManagedTypes;
|
||||
import org.springframework.orm.jpa.persistenceunit.PersistenceManagedTypesScanner;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.FactoryBean} that creates a JPA
|
||||
@@ -54,18 +65,26 @@ import org.springframework.util.Assert;
|
||||
* @since 2.0
|
||||
* @see #setJpaProperties
|
||||
* @see #setJpaVendorAdapter
|
||||
* @see JpaTransactionManager#setEntityManagerFactory
|
||||
* @see #setPersistenceConfiguration
|
||||
* @see #setDataSource
|
||||
* @see LocalContainerEntityManagerFactoryBean
|
||||
* @see org.springframework.jndi.JndiObjectFactoryBean
|
||||
* @see org.springframework.orm.jpa.support.SharedEntityManagerBean
|
||||
* @see jakarta.persistence.Persistence#createEntityManagerFactory
|
||||
* @see jakarta.persistence.spi.PersistenceProvider#createEntityManagerFactory
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class LocalEntityManagerFactoryBean extends AbstractEntityManagerFactoryBean {
|
||||
public class LocalEntityManagerFactoryBean extends AbstractEntityManagerFactoryBean implements ResourceLoaderAware {
|
||||
|
||||
private static final String NON_JTA_DATASOURCE_PROPERTY = "jakarta.persistence.nonJtaDataSource";
|
||||
|
||||
private static final String PACKAGE_INFO_SUFFIX = ".package-info";
|
||||
|
||||
|
||||
private @Nullable PersistenceConfiguration configuration;
|
||||
|
||||
private String @Nullable [] packagesToScan;
|
||||
|
||||
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
|
||||
|
||||
|
||||
/**
|
||||
* Create a {@code LocalEntityManagerFactoryBean}.
|
||||
@@ -151,6 +170,27 @@ public class LocalEntityManagerFactoryBean extends AbstractEntityManagerFactoryB
|
||||
super.setPersistenceUnitName(persistenceUnitName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use Spring-based scanning for entity classes in the classpath
|
||||
* instead of using JPA's standard scanning of jar files with {@code persistence.xml}
|
||||
* markers in them. In case of Spring-based scanning, no {@code persistence.xml}
|
||||
* is necessary; all you need to do is to specify base packages to search here.
|
||||
* <p>Default is none. Specify packages to search for autodetection of your entity
|
||||
* classes in the classpath. This is analogous to Spring's component-scan feature
|
||||
* ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}).
|
||||
* <p>The use of this setter switches this {@code LocalEntityManagerFactoryBean}
|
||||
* to a {@link #getPersistenceConfiguration() PersistenceConfiguration}, with no
|
||||
* {@code persistence.xml} reading or provider-driven scanning happening anymore.
|
||||
* Further JPA settings can be applied on the local {@link PersistenceConfiguration}
|
||||
* via {@link #getPersistenceConfiguration()}.
|
||||
* @since 7.0.4
|
||||
* @see LocalContainerEntityManagerFactoryBean#setPackagesToScan
|
||||
* @see org.springframework.orm.jpa.hibernate.LocalSessionFactoryBean#setPackagesToScan
|
||||
*/
|
||||
public void setPackagesToScan(String... packagesToScan) {
|
||||
this.packagesToScan = packagesToScan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the JDBC DataSource that the JPA persistence provider is supposed
|
||||
* to use for accessing the database. This is an alternative to keeping the
|
||||
@@ -165,9 +205,11 @@ public class LocalEntityManagerFactoryBean extends AbstractEntityManagerFactoryB
|
||||
public void setDataSource(@Nullable DataSource dataSource) {
|
||||
if (dataSource != null) {
|
||||
getJpaPropertyMap().put(PersistenceConfiguration.JDBC_DATASOURCE, dataSource);
|
||||
getJpaPropertyMap().put(NON_JTA_DATASOURCE_PROPERTY, dataSource);
|
||||
}
|
||||
else {
|
||||
getJpaPropertyMap().remove(PersistenceConfiguration.JDBC_DATASOURCE);
|
||||
getJpaPropertyMap().remove(NON_JTA_DATASOURCE_PROPERTY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,6 +224,11 @@ public class LocalEntityManagerFactoryBean extends AbstractEntityManagerFactoryB
|
||||
return (DataSource) getJpaPropertyMap().get(PersistenceConfiguration.JDBC_DATASOURCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the EntityManagerFactory for the given configuration.
|
||||
@@ -193,6 +240,25 @@ public class LocalEntityManagerFactoryBean extends AbstractEntityManagerFactoryB
|
||||
logger.debug("Building JPA EntityManagerFactory for persistence unit '" + getPersistenceUnitName() + "'");
|
||||
}
|
||||
|
||||
if (this.packagesToScan != null) {
|
||||
PersistenceManagedTypesScanner scanner = new PersistenceManagedTypesScanner(this.resourcePatternResolver);
|
||||
PersistenceManagedTypes result = scanner.scan(this.packagesToScan);
|
||||
// Expose managed class names from scan result (on JPA 4.0+, this includes
|
||||
// everything meta-annotated with @Discoverable, even package-info classes)
|
||||
Set<String> classNameSet = new LinkedHashSet<>(result.getManagedClassNames());
|
||||
// Expose managed packages as package-info class names if not included already
|
||||
// (accepted by PersistenceConfiguration on Hibernate as well as EclipseLink)
|
||||
for (String managedPackage : result.getManagedPackages()) {
|
||||
classNameSet.add(managedPackage + PACKAGE_INFO_SUFFIX);
|
||||
}
|
||||
// Expose pre-resolved Class references to PersistenceConfiguration.
|
||||
PersistenceConfiguration config = getPersistenceConfiguration();
|
||||
ClassLoader classLoader = this.resourcePatternResolver.getClassLoader();
|
||||
for (String className : classNameSet) {
|
||||
config.managedClass(ClassUtils.resolveClassName(className, classLoader));
|
||||
}
|
||||
}
|
||||
|
||||
if (this.configuration != null) {
|
||||
this.configuration.properties(getJpaPropertyMap());
|
||||
}
|
||||
@@ -204,8 +270,8 @@ public class LocalEntityManagerFactoryBean extends AbstractEntityManagerFactoryB
|
||||
provider.createEntityManagerFactory(this.configuration) :
|
||||
provider.createEntityManagerFactory(getPersistenceUnitName(), getJpaPropertyMap()));
|
||||
if (emf == null) {
|
||||
throw new IllegalStateException(
|
||||
"PersistenceProvider [" + provider + "] did not return an EntityManagerFactory for name '" +
|
||||
throw new PersistenceException(
|
||||
"PersistenceProvider [" + provider + "] could not find persistence unit for name '" +
|
||||
getPersistenceUnitName() + "'");
|
||||
}
|
||||
return emf;
|
||||
|
||||
Reference in New Issue
Block a user