Skip to content

Commit 4190209

Browse files
committed
Add missing AOT support for method overrides (including @lookup)
Closes gh-34642
1 parent cdf4c61 commit 4190209

File tree

7 files changed

+304
-109
lines changed

7 files changed

+304
-109
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@
5252
import org.springframework.beans.factory.support.AbstractBeanDefinition;
5353
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
5454
import org.springframework.beans.factory.support.InstanceSupplier;
55+
import org.springframework.beans.factory.support.LookupOverride;
56+
import org.springframework.beans.factory.support.MethodOverride;
57+
import org.springframework.beans.factory.support.ReplaceOverride;
5558
import org.springframework.beans.factory.support.RootBeanDefinition;
5659
import org.springframework.javapoet.CodeBlock;
5760
import org.springframework.javapoet.CodeBlock.Builder;
@@ -145,6 +148,7 @@ CodeBlock generateCode(RootBeanDefinition beanDefinition) {
145148
addPropertyValues(code, beanDefinition);
146149
addAttributes(code, beanDefinition);
147150
addQualifiers(code, beanDefinition);
151+
addMethodOverrides(code, beanDefinition);
148152
return code.build();
149153
}
150154

@@ -274,6 +278,36 @@ private void addQualifiers(CodeBlock.Builder code, RootBeanDefinition beanDefini
274278
}
275279
}
276280

281+
private void addMethodOverrides(CodeBlock.Builder code, RootBeanDefinition beanDefinition) {
282+
if (beanDefinition.hasMethodOverrides()) {
283+
for (MethodOverride methodOverride : beanDefinition.getMethodOverrides().getOverrides()) {
284+
if (methodOverride instanceof LookupOverride lookupOverride) {
285+
Collection<CodeBlock> arguments = new ArrayList<>();
286+
arguments.add(CodeBlock.of("$S", lookupOverride.getMethodName()));
287+
arguments.add(CodeBlock.of("$S", lookupOverride.getBeanName()));
288+
code.addStatement("$L.getMethodOverrides().addOverride(new $T($L))", BEAN_DEFINITION_VARIABLE,
289+
LookupOverride.class, CodeBlock.join(arguments, ", "));
290+
}
291+
else if (methodOverride instanceof ReplaceOverride replaceOverride) {
292+
Collection<CodeBlock> arguments = new ArrayList<>();
293+
arguments.add(CodeBlock.of("$S", replaceOverride.getMethodName()));
294+
arguments.add(CodeBlock.of("$S", replaceOverride.getMethodReplacerBeanName()));
295+
List<String> typeIdentifiers = replaceOverride.getTypeIdentifiers();
296+
if (!typeIdentifiers.isEmpty()) {
297+
arguments.add(CodeBlock.of("java.util.List.of($S)",
298+
StringUtils.collectionToDelimitedString(typeIdentifiers, ", ")));
299+
}
300+
code.addStatement("$L.getMethodOverrides().addOverride(new $T($L))", BEAN_DEFINITION_VARIABLE,
301+
ReplaceOverride.class, CodeBlock.join(arguments, ", "));
302+
}
303+
else {
304+
throw new UnsupportedOperationException("Unexpected MethodOverride subclass: " +
305+
methodOverride.getClass().getName());
306+
}
307+
}
308+
}
309+
}
310+
277311
private CodeBlock generateValue(@Nullable String name, @Nullable Object value) {
278312
PropertyNamesStack.push(name);
279313
try {

spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanInstanceSupplier.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.springframework.beans.factory.config.DependencyDescriptor;
3939
import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
4040
import org.springframework.beans.factory.support.BeanDefinitionValueResolver;
41+
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
4142
import org.springframework.beans.factory.support.InstanceSupplier;
4243
import org.springframework.beans.factory.support.RegisteredBean;
4344
import org.springframework.beans.factory.support.RootBeanDefinition;
@@ -372,6 +373,11 @@ private Object resolveAutowiredArgument(RegisteredBean registeredBean, Dependenc
372373

373374
private Object instantiate(RegisteredBean registeredBean, Executable executable, Object[] args) {
374375
if (executable instanceof Constructor<?> constructor) {
376+
if (registeredBean.getBeanFactory() instanceof DefaultListableBeanFactory dlbf &&
377+
registeredBean.getMergedBeanDefinition().hasMethodOverrides()) {
378+
return dlbf.getInstantiationStrategy().instantiate(registeredBean.getMergedBeanDefinition(),
379+
registeredBean.getBeanName(), registeredBean.getBeanFactory());
380+
}
375381
return BeanUtils.instantiateClass(constructor, args);
376382
}
377383
if (executable instanceof Method method) {

spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ public InstanceSupplierCodeGenerator(GenerationContext generationContext,
115115
this.allowDirectSupplierShortcut = allowDirectSupplierShortcut;
116116
}
117117

118+
118119
/**
119120
* Generate the instance supplier code.
120121
* @param registeredBean the bean to handle
@@ -165,7 +166,8 @@ private CodeBlock generateCodeForConstructor(RegisteredBean registeredBean, Cons
165166
hints -> hints.registerType(publicType, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS));
166167
}
167168

168-
if (!isVisible(constructor, constructor.getDeclaringClass())) {
169+
if (!isVisible(constructor, constructor.getDeclaringClass()) ||
170+
registeredBean.getMergedBeanDefinition().hasMethodOverrides()) {
169171
return generateCodeForInaccessibleConstructor(descriptor,
170172
hints -> hints.registerConstructor(constructor, ExecutableMode.INVOKE));
171173
}

spring-beans/src/main/java/org/springframework/beans/factory/support/ReplaceOverride.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.lang.reflect.Method;
2020
import java.util.ArrayList;
21+
import java.util.Collections;
2122
import java.util.List;
2223
import java.util.Objects;
2324

@@ -53,6 +54,20 @@ public ReplaceOverride(String methodName, String methodReplacerBeanName) {
5354
this.methodReplacerBeanName = methodReplacerBeanName;
5455
}
5556

57+
/**
58+
* Construct a new ReplaceOverride.
59+
* @param methodName the name of the method to override
60+
* @param methodReplacerBeanName the bean name of the {@link MethodReplacer}
61+
* @param typeIdentifiers a list of type identifiers for parameter types
62+
* @since 6.2.9
63+
*/
64+
public ReplaceOverride(String methodName, String methodReplacerBeanName, List<String> typeIdentifiers) {
65+
super(methodName);
66+
Assert.notNull(methodReplacerBeanName, "Method replacer bean name must not be null");
67+
this.methodReplacerBeanName = methodReplacerBeanName;
68+
this.typeIdentifiers.addAll(typeIdentifiers);
69+
}
70+
5671

5772
/**
5873
* Return the name of the bean implementing MethodReplacer.
@@ -70,6 +85,15 @@ public void addTypeIdentifier(String identifier) {
7085
this.typeIdentifiers.add(identifier);
7186
}
7287

88+
/**
89+
* Return the list of registered type identifiers (fragments of a class string).
90+
* @since 6.2.9
91+
* @see #addTypeIdentifier
92+
*/
93+
public List<String> getTypeIdentifiers() {
94+
return Collections.unmodifiableList(this.typeIdentifiers);
95+
}
96+
7397

7498
@Override
7599
public boolean matches(Method method) {

0 commit comments

Comments
 (0)