From 05ffe8249f366b145fc79c561da7a5fc9c4de912 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sat, 7 Feb 2026 21:01:25 +0100 Subject: [PATCH] Adapt to getAllClassNames SPI (post JPA 4.0 M1) See gh-35705 --- .../PersistenceManagedTypesScanner.java | 12 +++++++++++- .../persistenceunit/SpringPersistenceUnitInfo.java | 13 +++++-------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesScanner.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesScanner.java index 3bd3a50aafa..1dbe3e75915 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesScanner.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesScanner.java @@ -18,6 +18,7 @@ package org.springframework.orm.jpa.persistenceunit; import java.io.FileNotFoundException; import java.io.IOException; +import java.lang.annotation.Annotation; import java.net.URL; import java.util.ArrayList; import java.util.HashSet; @@ -72,6 +73,15 @@ public final class PersistenceManagedTypesScanner { entityTypeFilters.add(new AnnotationTypeFilter(Embeddable.class, false)); entityTypeFilters.add(new AnnotationTypeFilter(MappedSuperclass.class, false)); entityTypeFilters.add(new AnnotationTypeFilter(Converter.class, false)); + try { + @SuppressWarnings("unchecked") + Class discoverable = (Class) ClassUtils.forName( + "jakarta.persistence.spi.Discoverable", PersistenceManagedTypesScanner.class.getClassLoader()); + entityTypeFilters.add(new AnnotationTypeFilter(discoverable, true)); + } + catch (ClassNotFoundException ex) { + // JPA 4.0 API not present - simply skip. + } } private final ResourcePatternResolver resourcePatternResolver; @@ -147,7 +157,7 @@ public final class PersistenceManagedTypesScanner { } } } - else if (className.endsWith(PACKAGE_INFO_SUFFIX)) { + if (className.endsWith(PACKAGE_INFO_SUFFIX)) { scanResult.managedPackages.add(className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length())); } diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java index 6141eaa62e7..557f06b54fa 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java @@ -262,16 +262,13 @@ public class SpringPersistenceUnitInfo extends MutablePersistenceUnitInfo { // 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 mergedClassesAndPackages = new ArrayList<>(getManagedClassNames()); - mergedClassesAndPackages.addAll(getManagedPackages()); - return mergedClassesAndPackages; + else if (method.getName().equals("getAllClassNames")) { + // JPA 4.0 letting the container perform the scanning + if (excludeUnlistedClasses()) { + return getManagedClassNames(); // typically coming from Spring default persistence unit } throw new UnsupportedOperationException( - "JPA 4.0 getAllManagedClassNames only supported with exclude-unlisted-classes and no orm.xml"); + "JPA 4.0 getAllClassNames only supported with exclude-unlisted-classes"); } // Regular methods to be delegated to SpringPersistenceUnitInfo