Allow JPA entities to be filtered
This commit provides more control over JPA entities scanning by allowing the result to be filtered. Closes gh-27892
This commit is contained in:
committed by
Stéphane Nicoll
parent
6691ff2072
commit
472dcdb59c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -33,6 +33,7 @@ import org.springframework.instrument.classloading.LoadTimeWeaver;
|
||||
import org.springframework.jdbc.datasource.lookup.SingleDataSourceLookup;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager;
|
||||
import org.springframework.orm.jpa.persistenceunit.ManagedClassNameFilter;
|
||||
import org.springframework.orm.jpa.persistenceunit.PersistenceManagedTypes;
|
||||
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager;
|
||||
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;
|
||||
@@ -200,6 +201,16 @@ public class LocalContainerEntityManagerFactoryBean extends AbstractEntityManage
|
||||
this.internalPersistenceUnitManager.setPackagesToScan(packagesToScan);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ManagedClassNameFilter} to apply on entity classes discovered
|
||||
* using {@linkplain #setPackagesToScan(String...) classpath scanning}.
|
||||
* @param managedClassNameFilter the predicate to filter entity classes
|
||||
* @since 6.1.4
|
||||
*/
|
||||
public void setManagedClassNameFilter(ManagedClassNameFilter managedClassNameFilter) {
|
||||
this.internalPersistenceUnitManager.setManagedClassNameFilter(managedClassNameFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify one or more mapping resources (equivalent to {@code <mapping-file>}
|
||||
* entries in {@code persistence.xml}) for the default persistence unit.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -116,6 +116,9 @@ public class DefaultPersistenceUnitManager
|
||||
@Nullable
|
||||
private String[] packagesToScan;
|
||||
|
||||
@Nullable
|
||||
private ManagedClassNameFilter managedClassNameFilter;
|
||||
|
||||
@Nullable
|
||||
private String[] mappingResources;
|
||||
|
||||
@@ -223,6 +226,7 @@ public class DefaultPersistenceUnitManager
|
||||
* resource for the default unit if the mapping file is not co-located with a
|
||||
* {@code persistence.xml} file (in which case we assume it is only meant to be
|
||||
* used with the persistence units defined there, like in standard JPA).
|
||||
* @see #setManagedClassNameFilter(ManagedClassNameFilter)
|
||||
* @see #setManagedTypes(PersistenceManagedTypes)
|
||||
* @see #setDefaultPersistenceUnitName
|
||||
* @see #setMappingResources
|
||||
@@ -231,6 +235,16 @@ public class DefaultPersistenceUnitManager
|
||||
this.packagesToScan = packagesToScan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ManagedClassNameFilter} to apply on entity classes discovered
|
||||
* using {@linkplain #setPackagesToScan(String...) classpath scanning}.
|
||||
* @param managedClassNameFilter the predicate to filter entity classes
|
||||
* @since 6.1.4
|
||||
*/
|
||||
public void setManagedClassNameFilter(ManagedClassNameFilter managedClassNameFilter) {
|
||||
this.managedClassNameFilter = managedClassNameFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify one or more mapping resources (equivalent to {@code <mapping-file>}
|
||||
* entries in {@code persistence.xml}) for the default persistence unit.
|
||||
@@ -535,8 +549,9 @@ public class DefaultPersistenceUnitManager
|
||||
applyManagedTypes(scannedUnit, this.managedTypes);
|
||||
}
|
||||
else if (this.packagesToScan != null) {
|
||||
applyManagedTypes(scannedUnit, new PersistenceManagedTypesScanner(
|
||||
this.resourcePatternResolver).scan(this.packagesToScan));
|
||||
PersistenceManagedTypesScanner scanner = new PersistenceManagedTypesScanner(
|
||||
this.resourcePatternResolver, this.managedClassNameFilter);
|
||||
applyManagedTypes(scannedUnit, scanner.scan(this.packagesToScan));
|
||||
}
|
||||
|
||||
if (this.mappingResources != null) {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.orm.jpa.persistenceunit;
|
||||
|
||||
/**
|
||||
* Strategy interface to filter the list of persistent managed types to include
|
||||
* in the persistence unit. Only class names that match the filter are managed.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.1.4
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ManagedClassNameFilter {
|
||||
|
||||
/**
|
||||
* Test if the given clas name matches the filter.
|
||||
* @param className the fully qualified class name of the persistent type to test
|
||||
* @return {@code true} if the class name matches
|
||||
*/
|
||||
boolean matches(String className);
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -80,10 +80,20 @@ public final class PersistenceManagedTypesScanner {
|
||||
@Nullable
|
||||
private final CandidateComponentsIndex componentsIndex;
|
||||
|
||||
private final ManagedClassNameFilter managedClassNameFilter;
|
||||
|
||||
|
||||
public PersistenceManagedTypesScanner(ResourceLoader resourceLoader,
|
||||
@Nullable ManagedClassNameFilter managedClassNameFilter) {
|
||||
|
||||
public PersistenceManagedTypesScanner(ResourceLoader resourceLoader) {
|
||||
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
|
||||
this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(resourceLoader.getClassLoader());
|
||||
this.managedClassNameFilter = (managedClassNameFilter != null ? managedClassNameFilter
|
||||
: className -> true);
|
||||
}
|
||||
|
||||
public PersistenceManagedTypesScanner(ResourceLoader resourceLoader) {
|
||||
this(resourceLoader, null);
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +117,7 @@ public final class PersistenceManagedTypesScanner {
|
||||
for (AnnotationTypeFilter filter : entityTypeFilters) {
|
||||
candidates.addAll(this.componentsIndex.getCandidateTypes(pkg, filter.getAnnotationType().getName()));
|
||||
}
|
||||
scanResult.managedClassNames.addAll(candidates);
|
||||
scanResult.managedClassNames.addAll(candidates.stream().filter(this.managedClassNameFilter::matches).toList());
|
||||
scanResult.managedPackages.addAll(this.componentsIndex.getCandidateTypes(pkg, "package-info"));
|
||||
return;
|
||||
}
|
||||
@@ -121,7 +131,8 @@ public final class PersistenceManagedTypesScanner {
|
||||
try {
|
||||
MetadataReader reader = readerFactory.getMetadataReader(resource);
|
||||
String className = reader.getClassMetadata().getClassName();
|
||||
if (matchesFilter(reader, readerFactory)) {
|
||||
if (matchesEntityTypeFilter(reader, readerFactory)
|
||||
&& this.managedClassNameFilter.matches(className)) {
|
||||
scanResult.managedClassNames.add(className);
|
||||
if (scanResult.persistenceUnitRootUrl == null) {
|
||||
URL url = resource.getURL();
|
||||
@@ -157,7 +168,7 @@ public final class PersistenceManagedTypesScanner {
|
||||
* Check whether any of the configured entity type filters matches
|
||||
* the current class descriptor contained in the metadata reader.
|
||||
*/
|
||||
private boolean matchesFilter(MetadataReader reader, MetadataReaderFactory readerFactory) throws IOException {
|
||||
private boolean matchesEntityTypeFilter(MetadataReader reader, MetadataReaderFactory readerFactory) throws IOException {
|
||||
for (TypeFilter filter : entityTypeFilters) {
|
||||
if (filter.match(reader, readerFactory)) {
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user