diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java index c6f52fd611f..adc890d5426 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java @@ -137,6 +137,7 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr contributeConverterHints(hints, managedClass); contributeCallbackHints(hints, managedClass); contributeHibernateHints(hints, classLoader, managedClass); + contributePackagePrivateHints(hints, managedClass); } catch (ClassNotFoundException ex) { throw new IllegalArgumentException("Failed to instantiate JPA managed class: " + managedClassName, ex); @@ -234,6 +235,18 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr } } + private void contributePackagePrivateHints(RuntimeHints hints, Class managedClass) { + ReflectionHints reflection = hints.reflection(); + ReflectionUtils.doWithMethods(managedClass, method -> + reflection.registerMethod(method, ExecutableMode.INVOKE), + method -> { + int modifiers = method.getModifiers(); + return !(java.lang.reflect.Modifier.isProtected(modifiers) || + java.lang.reflect.Modifier.isPrivate(modifiers) || + java.lang.reflect.Modifier.isPublic(modifiers)); + }); + } + @SuppressWarnings("unchecked") private static @Nullable Class loadClass(String className, @Nullable ClassLoader classLoader) { try { diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/domain/Car.java b/spring-orm/src/test/java/org/springframework/orm/jpa/domain/Car.java new file mode 100644 index 00000000000..144e55fdfc4 --- /dev/null +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/domain/Car.java @@ -0,0 +1,50 @@ +/* + * Copyright 2002-present 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.domain; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +@Entity +public class Car { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Integer id; + + @Column + private String model; + + Integer getId() { + return id; + } + + void setId(Integer id) { + this.id = id; + } + + void setModel(String model) { + this.model = model; + } + + String getModel() { + return model; + } +} diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java b/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java index 6b45c4c81fb..238e87960c0 100644 --- a/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java @@ -38,6 +38,7 @@ import org.springframework.core.test.tools.Compiled; import org.springframework.core.test.tools.TestCompiler; import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.domain.Car; import org.springframework.orm.jpa.domain.DriversLicense; import org.springframework.orm.jpa.domain.Employee; import org.springframework.orm.jpa.domain.EmployeeCategoryConverter; @@ -71,7 +72,7 @@ class PersistenceManagedTypesBeanRegistrationAotProcessorTests { "persistenceManagedTypes", PersistenceManagedTypes.class); assertThat(persistenceManagedTypes.getManagedClassNames()).containsExactlyInAnyOrder( DriversLicense.class.getName(), Person.class.getName(), Employee.class.getName(), - EmployeeLocationConverter.class.getName()); + EmployeeLocationConverter.class.getName(), Car.class.getName()); assertThat(persistenceManagedTypes.getManagedPackages()).isEmpty(); assertThat(freshApplicationContext.getBean( JpaDomainConfiguration.class).scanningInvoked).isFalse(); @@ -104,6 +105,14 @@ class PersistenceManagedTypesBeanRegistrationAotProcessorTests { .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(hints); assertThat(RuntimeHintsPredicates.reflection().onType(EmployeeLocation.class) .withMemberCategories(MemberCategory.ACCESS_DECLARED_FIELDS)).accepts(hints); + assertThat(RuntimeHintsPredicates.reflection().onMethod(Car.class, "setId") + .invoke()).accepts(hints); + assertThat(RuntimeHintsPredicates.reflection().onMethod(Car.class, "getId") + .invoke()).accepts(hints); + assertThat(RuntimeHintsPredicates.reflection().onMethod(Car.class, "setModel") + .invoke()).accepts(hints); + assertThat(RuntimeHintsPredicates.reflection().onMethod(Car.class, "getModel") + .invoke()).accepts(hints); }); } diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesScannerTests.java b/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesScannerTests.java index c2ebac0e1f8..aee36ed2dc0 100644 --- a/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesScannerTests.java +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesScannerTests.java @@ -23,6 +23,7 @@ import org.junit.jupiter.api.Test; import org.springframework.context.testfixture.index.CandidateComponentsTestClassLoader; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.orm.jpa.domain.Car; import org.springframework.orm.jpa.domain.DriversLicense; import org.springframework.orm.jpa.domain.Employee; import org.springframework.orm.jpa.domain.EmployeeLocationConverter; @@ -52,7 +53,7 @@ class PersistenceManagedTypesScannerTests { PersistenceManagedTypes managedTypes = this.scanner.scan("org.springframework.orm.jpa.domain"); assertThat(managedTypes.getManagedClassNames()).containsExactlyInAnyOrder( Person.class.getName(), DriversLicense.class.getName(), Employee.class.getName(), - EmployeeLocationConverter.class.getName()); + EmployeeLocationConverter.class.getName(), Car.class.getName()); assertThat(managedTypes.getManagedPackages()).isEmpty(); } @@ -66,6 +67,7 @@ class PersistenceManagedTypesScannerTests { verify(filter).matches(DriversLicense.class.getName()); verify(filter).matches(Employee.class.getName()); verify(filter).matches(EmployeeLocationConverter.class.getName()); + verify(filter).matches(Car.class.getName()); verifyNoMoreInteractions(filter); }