diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContribution.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContribution.java index 110d55568957..d93e9507d68e 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContribution.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContribution.java @@ -16,6 +16,8 @@ package org.springframework.beans.factory.aot; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.Type; import java.util.Map; import javax.lang.model.element.Modifier; @@ -30,9 +32,11 @@ import org.springframework.aot.hint.ReflectionHints; import org.springframework.aot.hint.RuntimeHints; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.core.ResolvableType; import org.springframework.javapoet.ClassName; import org.springframework.javapoet.CodeBlock; import org.springframework.javapoet.MethodSpec; +import org.springframework.util.ReflectionUtils; /** * AOT contribution from a {@link BeanRegistrationsAotProcessor} used to @@ -118,6 +122,17 @@ private void generateRegisterHints(RuntimeHints runtimeHints, Map { + for (Type type : method.getGenericParameterTypes()) { + if (type instanceof GenericArrayType) { + Class clazz = ResolvableType.forType(type).resolve(); + if (clazz != null) { + hints.registerType(clazz); + } + } + } + }); }); } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContributionTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContributionTests.java index 48a3d1a217f7..833611e825db 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContributionTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContributionTests.java @@ -36,6 +36,8 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RegisteredBean; import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.testfixture.beans.GenericBeanWithBounds; +import org.springframework.beans.testfixture.beans.Person; import org.springframework.beans.testfixture.beans.RecordBean; import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.beans.testfixture.beans.factory.aot.MockBeanFactoryInitializationCode; @@ -161,6 +163,16 @@ void applyToRegisterReflectionHintsOnRecordBean() { .accepts(this.generationContext.getRuntimeHints()); } + @Test + void applyToRegisterReflectionHintsOnGenericBeanWithBounds() { + RegisteredBean registeredBean = registerBean(new RootBeanDefinition(GenericBeanWithBounds.class)); + BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(this.methodGeneratorFactory, + registeredBean, null, List.of()); + BeanRegistrationsAotContribution contribution = createContribution(GenericBeanWithBounds.class, generator); + contribution.applyTo(this.generationContext, this.beanFactoryInitializationCode); + assertThat(reflection().onType(Person[].class)).accepts(this.generationContext.getRuntimeHints()); + } + private RegisteredBean registerBean(RootBeanDefinition rootBeanDefinition) { String beanName = "testBean"; this.beanFactory.registerBeanDefinition(beanName, rootBeanDefinition); diff --git a/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/GenericBeanWithBounds.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/GenericBeanWithBounds.java new file mode 100644 index 000000000000..647c071cbfdc --- /dev/null +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/GenericBeanWithBounds.java @@ -0,0 +1,24 @@ +/* + * Copyright 2002-2023 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.beans.testfixture.beans; + +public class GenericBeanWithBounds { + + @SafeVarargs + public final void process(T... persons) { + } +}