Skip to content

Commit 74e5261

Browse files
Use ManagedType BeanDefinition for AOT processing when possible.
We now try to read the types directly from the bean definition arguments first, before attempting to resolve the actual bean instance. If resolving the bean fails, we currently only log an info message. This arrangement needs to be revisited. See: #2593
1 parent cfac788 commit 74e5261

File tree

2 files changed

+83
-4
lines changed

2 files changed

+83
-4
lines changed

src/main/java/org/springframework/data/aot/ManagedTypesBeanRegistrationAotProcessor.java

+39-3
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,20 @@
1515
*/
1616
package org.springframework.data.aot;
1717

18+
import java.util.Collection;
1819
import java.util.Collections;
1920
import java.util.Set;
2021

2122
import org.apache.commons.logging.Log;
2223
import org.apache.commons.logging.LogFactory;
23-
2424
import org.springframework.aot.generate.GenerationContext;
25+
import org.springframework.beans.factory.BeanCreationException;
2526
import org.springframework.beans.factory.BeanFactory;
2627
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
2728
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
29+
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
2830
import org.springframework.beans.factory.support.RegisteredBean;
31+
import org.springframework.beans.factory.support.RootBeanDefinition;
2932
import org.springframework.core.ResolvableType;
3033
import org.springframework.data.domain.ManagedTypes;
3134
import org.springframework.lang.Nullable;
@@ -53,8 +56,41 @@ public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registe
5356
}
5457

5558
BeanFactory beanFactory = registeredBean.getBeanFactory();
56-
return contribute(AotContext.from(registeredBean.getBeanFactory()),
57-
beanFactory.getBean(registeredBean.getBeanName(), ManagedTypes.class));
59+
return contribute(AotContext.from(beanFactory), resolveManagedTypes(registeredBean));
60+
}
61+
62+
ManagedTypes resolveManagedTypes(RegisteredBean registeredBean) {
63+
64+
RootBeanDefinition beanDefinition = registeredBean.getMergedBeanDefinition();
65+
if (beanDefinition.hasConstructorArgumentValues()) {
66+
ValueHolder indexedArgumentValue = beanDefinition.getConstructorArgumentValues().getIndexedArgumentValue(0, null);
67+
Object value = indexedArgumentValue.getValue();
68+
if (value instanceof Collection<?> values) {
69+
if (values.stream().allMatch(it -> it instanceof Class)) {
70+
return ManagedTypes.fromIterable((Collection<Class<?>>) values);
71+
}
72+
}
73+
}
74+
if (logger.isDebugEnabled()) {
75+
logger.debug(
76+
String.format("ManagedTypes BeanDefinition '%s' does serve arguments. Trying to resolve bean instance.",
77+
registeredBean.getBeanName()));
78+
}
79+
80+
if (registeredBean.getParent() == null) {
81+
try {
82+
return registeredBean.getBeanFactory().getBean(registeredBean.getBeanName(), ManagedTypes.class);
83+
} catch (BeanCreationException e) {
84+
if (logger.isInfoEnabled()) {
85+
logger.info(String.format("Could not resolve ManagedTypes '%s'.", registeredBean.getBeanName()));
86+
}
87+
if (logger.isDebugEnabled()) {
88+
logger.debug(e);
89+
}
90+
}
91+
}
92+
93+
return ManagedTypes.empty();
5894
}
5995

6096
protected boolean isMatch(@Nullable Class<?> beanType, @Nullable String beanName) {

src/test/java/org/springframework/data/aot/ManagedTypesBeanRegistrationAotProcessorUnitTests.java

+44-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package org.springframework.data.aot;
1717

1818
import static org.assertj.core.api.Assertions.*;
19+
import static org.mockito.ArgumentMatchers.*;
20+
import static org.mockito.Mockito.*;
1921

2022
import java.util.Collections;
2123
import java.util.function.Consumer;
@@ -28,6 +30,7 @@
2830
import org.springframework.aot.generate.InMemoryGeneratedFiles;
2931
import org.springframework.aot.hint.RuntimeHints;
3032
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
33+
import org.springframework.beans.factory.BeanCreationException;
3134
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
3235
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
3336
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
@@ -51,7 +54,7 @@ class ManagedTypesBeanRegistrationAotProcessorUnitTests {
5154

5255
@BeforeEach
5356
void beforeEach() {
54-
beanFactory = new DefaultListableBeanFactory();
57+
beanFactory = spy(new DefaultListableBeanFactory());
5558
}
5659

5760
@Test // GH-2593
@@ -65,6 +68,16 @@ void processesBeanWithMatchingModulePrefix() {
6568
assertThat(contribution).isNotNull();
6669
}
6770

71+
@Test // GH-2593
72+
void processesBeanDefinitionIfPossibleWithoutLoadingTheBean() {
73+
74+
beanFactory.registerBeanDefinition("commons.managed-types", managedTypesDefinition);
75+
76+
createPostProcessor("commons").processAheadOfTime(RegisteredBean.of(beanFactory, "commons.managed-types"));
77+
78+
verify(beanFactory, never()).getBean(eq("commons.managed-types"), eq(ManagedTypes.class));
79+
}
80+
6881
@Test // GH-2593
6982
void contributesReflectionForManagedTypes() {
7083

@@ -94,6 +107,16 @@ void processesMatchingSubtypeBean() {
94107
assertThat(contribution).isNotNull();
95108
}
96109

110+
@Test // GH-2593
111+
void processesMatchingSubtypeBeanByAttemptingToLoadItIfNoMatchingConstructorArgumentFound() {
112+
113+
beanFactory.registerBeanDefinition("commons.managed-types", myManagedTypesDefinition);
114+
115+
createPostProcessor("commons").processAheadOfTime(RegisteredBean.of(beanFactory, "commons.managed-types"));
116+
117+
verify(beanFactory).getBean(eq("commons.managed-types"), eq(ManagedTypes.class));
118+
}
119+
97120
@Test // GH-2593
98121
void ignoresBeanNotMatchingRequiredType() {
99122

@@ -117,6 +140,26 @@ void ignoresBeanNotMatchingPrefix() {
117140
assertThat(contribution).isNull();
118141
}
119142

143+
@Test // GH-2593
144+
void returnsEmptyContributionWhenBeanCannotBeLoaded() {
145+
146+
doThrow(new BeanCreationException("o_O")).when(beanFactory).getBean(eq("commons.managed-types"),
147+
eq(ManagedTypes.class));
148+
149+
beanFactory.registerBeanDefinition("commons.managed-types", myManagedTypesDefinition);
150+
151+
BeanRegistrationAotContribution contribution = createPostProcessor("commons")
152+
.processAheadOfTime(RegisteredBean.of(beanFactory, "commons.managed-types"));
153+
154+
DefaultGenerationContext generationContext = new DefaultGenerationContext(
155+
new GeneratedClasses(new ClassNameGenerator(Object.class)), new InMemoryGeneratedFiles(), new RuntimeHints());
156+
157+
contribution.applyTo(generationContext, null);
158+
159+
assertThat(generationContext.getRuntimeHints().reflection().typeHints()).isEmpty();
160+
verify(beanFactory).getBean(eq("commons.managed-types"), eq(ManagedTypes.class));
161+
}
162+
120163
private ManagedTypesBeanRegistrationAotProcessor createPostProcessor(String moduleIdentifier) {
121164
ManagedTypesBeanRegistrationAotProcessor postProcessor = new ManagedTypesBeanRegistrationAotProcessor();
122165
postProcessor.setModuleIdentifier(moduleIdentifier);

0 commit comments

Comments
 (0)