diff --git a/spring-core/src/main/java/org/springframework/util/ClassUtils.java b/spring-core/src/main/java/org/springframework/util/ClassUtils.java index 50800d0c977..56cfedf091f 100644 --- a/spring-core/src/main/java/org/springframework/util/ClassUtils.java +++ b/spring-core/src/main/java/org/springframework/util/ClassUtils.java @@ -94,6 +94,12 @@ public abstract class ClassUtils { /** The ".class" file suffix. */ public static final String CLASS_FILE_SUFFIX = ".class"; + /** + * The ".package-info" suffix for package class names. + * @since 7.0.8 + */ + public static final String PACKAGE_INFO_SUFFIX = ".package-info"; + /** Precomputed value for the combination of private, static and final modifiers. */ private static final int NON_OVERRIDABLE_MODIFIER = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL; diff --git a/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileAnnotationMetadata.java b/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileAnnotationMetadata.java index 2ddf9844fcd..0394fb99bd9 100644 --- a/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileAnnotationMetadata.java +++ b/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileAnnotationMetadata.java @@ -78,7 +78,7 @@ final class ClassFileAnnotationMetadata implements AnnotationMetadata { this.className = className; this.accessFlags = accessFlags; this.enclosingClassName = enclosingClassName; - this.superClassName = (!className.endsWith(".package-info")) ? superClassName : null; + this.superClassName = (!className.endsWith(ClassUtils.PACKAGE_INFO_SUFFIX) ? superClassName : null); this.independentInnerClass = independentInnerClass; this.interfaceNames = interfaceNames; this.memberClassNames = memberClassNames; diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/LocalEntityManagerFactoryBean.java b/spring-orm/src/main/java/org/springframework/orm/jpa/LocalEntityManagerFactoryBean.java index 0880b12ac1e..087cad8f122 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/LocalEntityManagerFactoryBean.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/LocalEntityManagerFactoryBean.java @@ -76,9 +76,6 @@ public class LocalEntityManagerFactoryBean extends AbstractEntityManagerFactoryB 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; @@ -249,7 +246,7 @@ public class LocalEntityManagerFactoryBean extends AbstractEntityManagerFactoryB // 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); + classNameSet.add(managedPackage + ClassUtils.PACKAGE_INFO_SUFFIX); } // Expose pre-resolved Class references to PersistenceConfiguration. PersistenceConfiguration config = getPersistenceConfiguration(); diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/hibernate/LocalSessionFactoryBuilder.java b/spring-orm/src/main/java/org/springframework/orm/jpa/hibernate/LocalSessionFactoryBuilder.java index 31c51341510..135f48de803 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/hibernate/LocalSessionFactoryBuilder.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/hibernate/LocalSessionFactoryBuilder.java @@ -103,8 +103,6 @@ public class LocalSessionFactoryBuilder extends Configuration { private static final String RESOURCE_PATTERN = "/**/*.class"; - private static final String PACKAGE_INFO_SUFFIX = ".package-info"; - private static final TypeFilter[] DEFAULT_ENTITY_TYPE_FILTERS = new TypeFilter[] { new AnnotationTypeFilter(Entity.class, false), new AnnotationTypeFilter(Embeddable.class, false), @@ -312,8 +310,9 @@ public class LocalSessionFactoryBuilder extends Configuration { else if (CONVERTER_TYPE_FILTER.match(reader, readerFactory)) { converterClassNames.add(className); } - else if (className.endsWith(PACKAGE_INFO_SUFFIX)) { - packageNames.add(className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length())); + else if (className.endsWith(ClassUtils.PACKAGE_INFO_SUFFIX)) { + packageNames.add(className.substring(0, + className.length() - ClassUtils.PACKAGE_INFO_SUFFIX.length())); } } catch (FileNotFoundException ex) { 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 1dbe3e75915..9d663f7390f 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 @@ -59,8 +59,6 @@ public final class PersistenceManagedTypesScanner { private static final String CLASS_RESOURCE_PATTERN = "/**/*.class"; - private static final String PACKAGE_INFO_SUFFIX = ".package-info"; - private static final String IGNORE_CLASSFORMAT_PROPERTY_NAME = "spring.classformat.ignore"; private static final boolean shouldIgnoreClassFormatException = @@ -157,9 +155,9 @@ public final class PersistenceManagedTypesScanner { } } } - if (className.endsWith(PACKAGE_INFO_SUFFIX)) { + if (className.endsWith(ClassUtils.PACKAGE_INFO_SUFFIX)) { scanResult.managedPackages.add(className.substring(0, - className.length() - PACKAGE_INFO_SUFFIX.length())); + className.length() - ClassUtils.PACKAGE_INFO_SUFFIX.length())); } } catch (FileNotFoundException ex) { 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 557f06b54fa..dc1051f5cf5 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 @@ -264,11 +264,18 @@ public class SpringPersistenceUnitInfo extends MutablePersistenceUnitInfo { } 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 + if (excludeUnlistedClasses()) { // typically coming from Spring default persistence unit + List mergedClassesAndPackages = + new ArrayList<>(getManagedClassNames().size() + getManagedPackages().size()); + mergedClassesAndPackages.addAll(getManagedClassNames()); + for (String managedPackage : getManagedPackages()) { + mergedClassesAndPackages.add(managedPackage + ClassUtils.PACKAGE_INFO_SUFFIX); + } + return mergedClassesAndPackages; } throw new UnsupportedOperationException( - "JPA 4.0 getAllClassNames only supported with exclude-unlisted-classes"); + "JPA 4.0 getAllClassNames only supported with Spring-configured packagesToScan or " + + "with completely listed managed classes plus exclude-unlisted-classes=true"); } // Regular methods to be delegated to SpringPersistenceUnitInfo