Skip to content

Commit 8a4a89b

Browse files
committed
Allow a MethodReference to be produced from a GeneratedMethod
This commit updates GeneratedMethod and its underlying infrastructure to be able to produce a MethodReference. This simplifies the need when such a reference needs to be created manually and reuses more of what MethodReference has to offer. See gh-29005
1 parent 649c2f5 commit 8a4a89b

File tree

14 files changed

+101
-43
lines changed

14 files changed

+101
-43
lines changed

spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyBeanRegistrationAotProcessor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,8 @@ public CodeBlock generateInstanceSupplierCode(GenerationContext generationContex
163163
method.addStatement("return ($T) factory.getObject()",
164164
beanClass);
165165
});
166-
return CodeBlock.of("$T.of($T::$L)", InstanceSupplier.class,
167-
beanRegistrationCode.getClassName(), generatedMethod.getName());
166+
return CodeBlock.of("$T.of($L)", InstanceSupplier.class,
167+
generatedMethod.toMethodReference().toCodeBlock());
168168
}
169169

170170
}

spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
import org.springframework.aot.generate.GeneratedClass;
4545
import org.springframework.aot.generate.GeneratedMethod;
4646
import org.springframework.aot.generate.GenerationContext;
47-
import org.springframework.aot.generate.MethodReference;
4847
import org.springframework.aot.hint.ExecutableMode;
4948
import org.springframework.aot.hint.RuntimeHints;
5049
import org.springframework.beans.BeanUtils;
@@ -944,8 +943,7 @@ public void applyTo(GenerationContext generationContext,
944943
method.returns(this.target);
945944
method.addCode(generateMethodCode(generationContext.getRuntimeHints()));
946945
});
947-
beanRegistrationCode.addInstancePostProcessor(
948-
MethodReference.ofStatic(generatedClass.getName(), generateMethod.getName()));
946+
beanRegistrationCode.addInstancePostProcessor(generateMethod.toMethodReference());
949947

950948
if (this.candidateResolver != null) {
951949
registerHints(generationContext.getRuntimeHints());

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,16 +107,14 @@ MethodReference generateBeanDefinitionMethod(GenerationContext generationContext
107107
GeneratedMethod generatedMethod = generateBeanDefinitionMethod(
108108
generationContext, generatedClass.getName(), generatedMethods,
109109
codeFragments, Modifier.PUBLIC);
110-
return MethodReference.ofStatic(generatedClass.getName(),
111-
generatedMethod.getName());
110+
return generatedMethod.toMethodReference();
112111
}
113112
GeneratedMethods generatedMethods = beanRegistrationsCode.getMethods()
114113
.withPrefix(getName());
115114
GeneratedMethod generatedMethod = generateBeanDefinitionMethod(generationContext,
116115
beanRegistrationsCode.getClassName(), generatedMethods, codeFragments,
117116
Modifier.PRIVATE);
118-
return MethodReference.ofStatic(beanRegistrationsCode.getClassName(),
119-
generatedMethod.getName());
117+
return generatedMethod.toMethodReference();
120118
}
121119

122120
private BeanRegistrationCodeFragments getCodeFragments(GenerationContext generationContext,

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,7 @@ public void applyTo(GenerationContext generationContext,
6565
BeanRegistrationsCodeGenerator codeGenerator = new BeanRegistrationsCodeGenerator(generatedClass);
6666
GeneratedMethod generatedMethod = codeGenerator.getMethods().add("registerBeanDefinitions", method ->
6767
generateRegisterMethod(method, generationContext, codeGenerator));
68-
beanFactoryInitializationCode.addInitializer(
69-
MethodReference.of(generatedClass.getName(), generatedMethod.getName()));
68+
beanFactoryInitializationCode.addInitializer(generatedMethod.toMethodReference());
7069
}
7170

7271
private void generateRegisterMethod(MethodSpec.Builder method,

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,8 @@ private CodeBlock generateNewInstanceCodeForMethod(boolean dependsOnBean,
296296
REGISTERED_BEAN_PARAMETER_NAME, declaringClass, factoryMethodName, args);
297297
}
298298

299-
private CodeBlock generateReturnStatement(GeneratedMethod getInstanceMethod) {
300-
return CodeBlock.of("$T.$L()", this.className, getInstanceMethod.getName());
299+
private CodeBlock generateReturnStatement(GeneratedMethod generatedMethod) {
300+
return generatedMethod.toMethodReference().toInvokeCodeBlock();
301301
}
302302

303303
private CodeBlock generateWithGeneratorCode(boolean hasArguments, CodeBlock newInstance) {

spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGeneratorTests.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,7 @@ void generateBeanDefinitionMethodWhenHasInstancePostProcessorGeneratesMethod() {
129129
.addParameter(RegisteredBean.class, "registeredBean")
130130
.addParameter(TestBean.class, "testBean")
131131
.returns(TestBean.class).addCode("return new $T($S);", TestBean.class, "postprocessed"));
132-
beanRegistrationCode.addInstancePostProcessor(MethodReference.ofStatic(
133-
beanRegistrationCode.getClassName(), generatedMethod.getName()));
132+
beanRegistrationCode.addInstancePostProcessor(generatedMethod.toMethodReference());
134133
};
135134
List<BeanRegistrationAotContribution> aotContributions = Collections
136135
.singletonList(aotContribution);
@@ -167,8 +166,7 @@ void generateBeanDefinitionMethodWhenHasInstancePostProcessorAndFactoryMethodGen
167166
.addParameter(RegisteredBean.class, "registeredBean")
168167
.addParameter(TestBean.class, "testBean")
169168
.returns(TestBean.class).addCode("return new $T($S);", TestBean.class, "postprocessed"));
170-
beanRegistrationCode.addInstancePostProcessor(MethodReference.ofStatic(
171-
beanRegistrationCode.getClassName(), generatedMethod.getName()));
169+
beanRegistrationCode.addInstancePostProcessor(generatedMethod.toMethodReference());
172170
};
173171
List<BeanRegistrationAotContribution> aotContributions = Collections
174172
.singletonList(aotContribution);

spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import org.springframework.aop.framework.autoproxy.AutoProxyUtils;
3434
import org.springframework.aot.generate.GeneratedMethod;
3535
import org.springframework.aot.generate.GenerationContext;
36-
import org.springframework.aot.generate.MethodReference;
3736
import org.springframework.aot.hint.ResourceHints;
3837
import org.springframework.aot.hint.TypeReference;
3938
import org.springframework.beans.PropertyValues;
@@ -536,7 +535,7 @@ public void applyTo(GenerationContext generationContext,
536535
.add("addImportAwareBeanPostProcessors", method ->
537536
generateAddPostProcessorMethod(method, mappings));
538537
beanFactoryInitializationCode
539-
.addInitializer(MethodReference.of(generatedMethod.getName()));
538+
.addInitializer(generatedMethod.toMethodReference());
540539
ResourceHints hints = generationContext.getRuntimeHints().resources();
541540
mappings.forEach(
542541
(target, from) -> hints.registerType(TypeReference.of(from)));

spring-core/src/main/java/org/springframework/aot/generate/GeneratedClass.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public final class GeneratedClass {
5555
GeneratedClass(ClassName name, Consumer<TypeSpec.Builder> type) {
5656
this.name = name;
5757
this.type = type;
58-
this.methods = new GeneratedMethods(this::generateSequencedMethodName);
58+
this.methods = new GeneratedMethods(name, this::generateSequencedMethodName);
5959
}
6060

6161

spring-core/src/main/java/org/springframework/aot/generate/GeneratedMethod.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,24 @@
1818

1919
import java.util.function.Consumer;
2020

21+
import javax.lang.model.element.Modifier;
22+
23+
import org.springframework.javapoet.ClassName;
2124
import org.springframework.javapoet.MethodSpec;
2225
import org.springframework.util.Assert;
2326

2427
/**
2528
* A generated method.
2629
*
2730
* @author Phillip Webb
31+
* @author Stephane Nicoll
2832
* @since 6.0
2933
* @see GeneratedMethods
3034
*/
3135
public final class GeneratedMethod {
3236

37+
private final ClassName className;
38+
3339
private final String name;
3440

3541
private final MethodSpec methodSpec;
@@ -39,12 +45,14 @@ public final class GeneratedMethod {
3945
* Create a new {@link GeneratedMethod} instance with the given name. This
4046
* constructor is package-private since names should only be generated via
4147
* {@link GeneratedMethods}.
48+
* @param className the declaring class of the method
4249
* @param name the generated method name
4350
* @param method consumer to generate the method
4451
*/
45-
GeneratedMethod(String name, Consumer<MethodSpec.Builder> method) {
52+
GeneratedMethod(ClassName className, String name, Consumer<MethodSpec.Builder> method) {
53+
this.className = className;
4654
this.name = name;
47-
MethodSpec.Builder builder = MethodSpec.methodBuilder(getName());
55+
MethodSpec.Builder builder = MethodSpec.methodBuilder(this.name);
4856
method.accept(builder);
4957
this.methodSpec = builder.build();
5058
Assert.state(this.name.equals(this.methodSpec.name),
@@ -60,6 +68,16 @@ public String getName() {
6068
return this.name;
6169
}
6270

71+
/**
72+
* Return a {@link MethodReference} to this generated method.
73+
* @return a method reference
74+
*/
75+
public MethodReference toMethodReference() {
76+
return (this.methodSpec.modifiers.contains(Modifier.STATIC)
77+
? MethodReference.ofStatic(this.className, this.name)
78+
: MethodReference.of(this.className, this.name));
79+
}
80+
6381
/**
6482
* Return the {@link MethodSpec} for this generated method.
6583
* @return the method spec

spring-core/src/main/java/org/springframework/aot/generate/GeneratedMethods.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.function.Function;
2323
import java.util.stream.Stream;
2424

25+
import org.springframework.javapoet.ClassName;
2526
import org.springframework.javapoet.MethodSpec;
2627
import org.springframework.javapoet.MethodSpec.Builder;
2728
import org.springframework.util.Assert;
@@ -30,11 +31,14 @@
3031
* A managed collection of generated methods.
3132
*
3233
* @author Phillip Webb
34+
* @author Stephane Nicoll
3335
* @since 6.0
3436
* @see GeneratedMethod
3537
*/
3638
public class GeneratedMethods {
3739

40+
private final ClassName className;
41+
3842
private final Function<MethodName, String> methodNameGenerator;
3943

4044
private final MethodName prefix;
@@ -44,18 +48,22 @@ public class GeneratedMethods {
4448
/**
4549
* Create a new {@link GeneratedMethods} using the specified method name
4650
* generator.
51+
* @param className the declaring class name
4752
* @param methodNameGenerator the method name generator
4853
*/
49-
GeneratedMethods(Function<MethodName, String> methodNameGenerator) {
54+
GeneratedMethods(ClassName className, Function<MethodName, String> methodNameGenerator) {
55+
Assert.notNull(className, "'className' must not be null");
5056
Assert.notNull(methodNameGenerator, "'methodNameGenerator' must not be null");
57+
this.className = className;
5158
this.methodNameGenerator = methodNameGenerator;
5259
this.prefix = MethodName.NONE;
5360
this.generatedMethods = new ArrayList<>();
5461
}
5562

56-
private GeneratedMethods(Function<MethodName, String> methodNameGenerator,
63+
private GeneratedMethods(ClassName className, Function<MethodName, String> methodNameGenerator,
5764
MethodName prefix, List<GeneratedMethod> generatedMethods) {
5865

66+
this.className = className;
5967
this.methodNameGenerator = methodNameGenerator;
6068
this.prefix = prefix;
6169
this.generatedMethods = generatedMethods;
@@ -82,15 +90,16 @@ public GeneratedMethod add(String[] suggestedNameParts, Consumer<Builder> method
8290
Assert.notNull(suggestedNameParts, "'suggestedNameParts' must not be null");
8391
Assert.notNull(method, "'method' must not be null");
8492
String generatedName = this.methodNameGenerator.apply(this.prefix.and(suggestedNameParts));
85-
GeneratedMethod generatedMethod = new GeneratedMethod(generatedName, method);
93+
GeneratedMethod generatedMethod = new GeneratedMethod(this.className, generatedName, method);
8694
this.generatedMethods.add(generatedMethod);
8795
return generatedMethod;
8896
}
8997

9098

9199
public GeneratedMethods withPrefix(String prefix) {
92100
Assert.notNull(prefix, "'prefix' must not be null");
93-
return new GeneratedMethods(this.methodNameGenerator, this.prefix.and(prefix), this.generatedMethods);
101+
return new GeneratedMethods(this.className, this.methodNameGenerator,
102+
this.prefix.and(prefix), this.generatedMethods);
94103
}
95104

96105
/**

spring-core/src/test/java/org/springframework/aot/generate/GeneratedMethodTests.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,12 @@
1818

1919
import java.util.function.Consumer;
2020

21+
import javax.lang.model.element.Modifier;
22+
2123
import org.junit.jupiter.api.Test;
2224

25+
import org.springframework.javapoet.ClassName;
26+
import org.springframework.javapoet.CodeBlock;
2327
import org.springframework.javapoet.MethodSpec;
2428

2529
import static org.assertj.core.api.Assertions.assertThat;
@@ -29,30 +33,55 @@
2933
* Tests for {@link GeneratedMethod}.
3034
*
3135
* @author Phillip Webb
36+
* @author Stephane Nicoll
3237
*/
3338
class GeneratedMethodTests {
3439

35-
private static final Consumer<MethodSpec.Builder> methodSpecCustomizer = method -> {};
40+
private static final ClassName TEST_CLASS_NAME = ClassName.get("com.example", "Test");
41+
42+
private static final Consumer<MethodSpec.Builder> emptyMethod = method -> {};
3643

3744
private static final String NAME = "spring";
3845

3946
@Test
4047
void getNameReturnsName() {
41-
GeneratedMethod generatedMethod = new GeneratedMethod(NAME, methodSpecCustomizer);
48+
GeneratedMethod generatedMethod = new GeneratedMethod(TEST_CLASS_NAME, NAME, emptyMethod);
4249
assertThat(generatedMethod.getName()).isSameAs(NAME);
4350
}
4451

4552
@Test
4653
void generateMethodSpecReturnsMethodSpec() {
47-
GeneratedMethod generatedMethod = new GeneratedMethod(NAME, method -> method.addJavadoc("Test"));
54+
GeneratedMethod generatedMethod = create(method -> method.addJavadoc("Test"));
4855
assertThat(generatedMethod.getMethodSpec().javadoc).asString().contains("Test");
4956
}
5057

5158
@Test
5259
void generateMethodSpecWhenMethodNameIsChangedThrowsException() {
5360
assertThatIllegalStateException().isThrownBy(() ->
54-
new GeneratedMethod(NAME, method -> method.setName("badname")).getMethodSpec())
55-
.withMessage("'method' consumer must not change the generated method name");
61+
create(method -> method.setName("badname")).getMethodSpec())
62+
.withMessage("'method' consumer must not change the generated method name");
63+
}
64+
65+
@Test
66+
void toMethodReferenceWithInstanceMethod() {
67+
GeneratedMethod generatedMethod = create(emptyMethod);
68+
MethodReference methodReference = generatedMethod.toMethodReference();
69+
assertThat(methodReference).isNotNull();
70+
assertThat(methodReference.toInvokeCodeBlock("test"))
71+
.isEqualTo(CodeBlock.of("test.spring()"));
72+
}
73+
74+
@Test
75+
void toMethodReferenceWithStaticMethod() {
76+
GeneratedMethod generatedMethod = create(method -> method.addModifiers(Modifier.STATIC));
77+
MethodReference methodReference = generatedMethod.toMethodReference();
78+
assertThat(methodReference).isNotNull();
79+
assertThat(methodReference.toInvokeCodeBlock())
80+
.isEqualTo(CodeBlock.of("com.example.Test.spring()"));
81+
}
82+
83+
private GeneratedMethod create(Consumer<MethodSpec.Builder> method) {
84+
return new GeneratedMethod(TEST_CLASS_NAME, NAME, method);
5685
}
5786

5887
}

spring-core/src/test/java/org/springframework/aot/generate/GeneratedMethodsTests.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import org.junit.jupiter.api.Test;
2525

26+
import org.springframework.javapoet.ClassName;
2627
import org.springframework.javapoet.MethodSpec;
2728

2829
import static org.assertj.core.api.Assertions.assertThat;
@@ -32,46 +33,57 @@
3233
* Tests for {@link GeneratedMethods}.
3334
*
3435
* @author Phillip Webb
36+
* @author Stephane Nicoll
3537
*/
3638
class GeneratedMethodsTests {
3739

40+
private static final ClassName TEST_CLASS_NAME = ClassName.get("com.example", "Test");
41+
3842
private static final Consumer<MethodSpec.Builder> methodSpecCustomizer = method -> {};
3943

40-
private final GeneratedMethods methods = new GeneratedMethods(MethodName::toString);
44+
private final GeneratedMethods methods = new GeneratedMethods(TEST_CLASS_NAME, MethodName::toString);
45+
46+
@Test
47+
void createWhenClassNameIsNullThrowsException() {
48+
assertThatIllegalArgumentException().isThrownBy(() ->
49+
new GeneratedMethods(null, MethodName::toString))
50+
.withMessage("'className' must not be null");
51+
}
4152

4253
@Test
4354
void createWhenMethodNameGeneratorIsNullThrowsException() {
44-
assertThatIllegalArgumentException().isThrownBy(() -> new GeneratedMethods(null))
55+
assertThatIllegalArgumentException().isThrownBy(() ->
56+
new GeneratedMethods(TEST_CLASS_NAME, null))
4557
.withMessage("'methodNameGenerator' must not be null");
4658
}
4759

4860
@Test
4961
void createWithExistingGeneratorUsesGenerator() {
5062
Function<MethodName, String> generator = name -> "__" + name.toString();
51-
GeneratedMethods methods = new GeneratedMethods(generator);
63+
GeneratedMethods methods = new GeneratedMethods(TEST_CLASS_NAME, generator);
5264
assertThat(methods.add("test", methodSpecCustomizer).getName()).hasToString("__test");
5365
}
5466

5567
@Test
5668
void addWithStringNameWhenSuggestedMethodIsNullThrowsException() {
5769
assertThatIllegalArgumentException().isThrownBy(() ->
58-
this.methods.add((String) null, methodSpecCustomizer))
59-
.withMessage("'suggestedName' must not be null");
70+
this.methods.add((String) null, methodSpecCustomizer))
71+
.withMessage("'suggestedName' must not be null");
6072
}
6173

6274
@Test
6375
void addWithStringNameWhenMethodIsNullThrowsException() {
6476
assertThatIllegalArgumentException().isThrownBy(() ->
65-
this.methods.add("test", null))
66-
.withMessage("'method' must not be null");
77+
this.methods.add("test", null))
78+
.withMessage("'method' must not be null");
6779
}
6880

6981
@Test
7082
void addAddsMethod() {
7183
this.methods.add("springBeans", methodSpecCustomizer);
7284
this.methods.add("springContext", methodSpecCustomizer);
7385
assertThat(this.methods.stream().map(GeneratedMethod::getName).map(Object::toString))
74-
.containsExactly("springBeans", "springContext");
86+
.containsExactly("springBeans", "springContext");
7587
}
7688

7789
@Test

spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public CodeBlock generateInstanceSupplierCode(GenerationContext generationContex
9999
List.class, toCodeBlock(persistenceManagedTypes.getManagedPackages()));
100100
method.addStatement("return $T.of($L, $L)", beanType, "managedClassNames", "managedPackages");
101101
});
102-
return CodeBlock.of("() -> $T.$L()", beanRegistrationCode.getClassName(), generatedMethod.getName());
102+
return generatedMethod.toMethodReference().toCodeBlock();
103103
}
104104

105105
private CodeBlock toCodeBlock(List<String> values) {

0 commit comments

Comments
 (0)