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
This commit is contained in:
parent
649c2f56fd
commit
8a4a89b9d9
|
@ -163,8 +163,8 @@ class ScopedProxyBeanRegistrationAotProcessor implements BeanRegistrationAotProc
|
|||
method.addStatement("return ($T) factory.getObject()",
|
||||
beanClass);
|
||||
});
|
||||
return CodeBlock.of("$T.of($T::$L)", InstanceSupplier.class,
|
||||
beanRegistrationCode.getClassName(), generatedMethod.getName());
|
||||
return CodeBlock.of("$T.of($L)", InstanceSupplier.class,
|
||||
generatedMethod.toMethodReference().toCodeBlock());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,7 +44,6 @@ import org.springframework.aot.generate.AccessVisibility;
|
|||
import org.springframework.aot.generate.GeneratedClass;
|
||||
import org.springframework.aot.generate.GeneratedMethod;
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.aot.generate.MethodReference;
|
||||
import org.springframework.aot.hint.ExecutableMode;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
@ -944,8 +943,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
|||
method.returns(this.target);
|
||||
method.addCode(generateMethodCode(generationContext.getRuntimeHints()));
|
||||
});
|
||||
beanRegistrationCode.addInstancePostProcessor(
|
||||
MethodReference.ofStatic(generatedClass.getName(), generateMethod.getName()));
|
||||
beanRegistrationCode.addInstancePostProcessor(generateMethod.toMethodReference());
|
||||
|
||||
if (this.candidateResolver != null) {
|
||||
registerHints(generationContext.getRuntimeHints());
|
||||
|
|
|
@ -107,16 +107,14 @@ class BeanDefinitionMethodGenerator {
|
|||
GeneratedMethod generatedMethod = generateBeanDefinitionMethod(
|
||||
generationContext, generatedClass.getName(), generatedMethods,
|
||||
codeFragments, Modifier.PUBLIC);
|
||||
return MethodReference.ofStatic(generatedClass.getName(),
|
||||
generatedMethod.getName());
|
||||
return generatedMethod.toMethodReference();
|
||||
}
|
||||
GeneratedMethods generatedMethods = beanRegistrationsCode.getMethods()
|
||||
.withPrefix(getName());
|
||||
GeneratedMethod generatedMethod = generateBeanDefinitionMethod(generationContext,
|
||||
beanRegistrationsCode.getClassName(), generatedMethods, codeFragments,
|
||||
Modifier.PRIVATE);
|
||||
return MethodReference.ofStatic(beanRegistrationsCode.getClassName(),
|
||||
generatedMethod.getName());
|
||||
return generatedMethod.toMethodReference();
|
||||
}
|
||||
|
||||
private BeanRegistrationCodeFragments getCodeFragments(GenerationContext generationContext,
|
||||
|
|
|
@ -65,8 +65,7 @@ class BeanRegistrationsAotContribution
|
|||
BeanRegistrationsCodeGenerator codeGenerator = new BeanRegistrationsCodeGenerator(generatedClass);
|
||||
GeneratedMethod generatedMethod = codeGenerator.getMethods().add("registerBeanDefinitions", method ->
|
||||
generateRegisterMethod(method, generationContext, codeGenerator));
|
||||
beanFactoryInitializationCode.addInitializer(
|
||||
MethodReference.of(generatedClass.getName(), generatedMethod.getName()));
|
||||
beanFactoryInitializationCode.addInitializer(generatedMethod.toMethodReference());
|
||||
}
|
||||
|
||||
private void generateRegisterMethod(MethodSpec.Builder method,
|
||||
|
|
|
@ -296,8 +296,8 @@ class InstanceSupplierCodeGenerator {
|
|||
REGISTERED_BEAN_PARAMETER_NAME, declaringClass, factoryMethodName, args);
|
||||
}
|
||||
|
||||
private CodeBlock generateReturnStatement(GeneratedMethod getInstanceMethod) {
|
||||
return CodeBlock.of("$T.$L()", this.className, getInstanceMethod.getName());
|
||||
private CodeBlock generateReturnStatement(GeneratedMethod generatedMethod) {
|
||||
return generatedMethod.toMethodReference().toInvokeCodeBlock();
|
||||
}
|
||||
|
||||
private CodeBlock generateWithGeneratorCode(boolean hasArguments, CodeBlock newInstance) {
|
||||
|
|
|
@ -129,8 +129,7 @@ class BeanDefinitionMethodGeneratorTests {
|
|||
.addParameter(RegisteredBean.class, "registeredBean")
|
||||
.addParameter(TestBean.class, "testBean")
|
||||
.returns(TestBean.class).addCode("return new $T($S);", TestBean.class, "postprocessed"));
|
||||
beanRegistrationCode.addInstancePostProcessor(MethodReference.ofStatic(
|
||||
beanRegistrationCode.getClassName(), generatedMethod.getName()));
|
||||
beanRegistrationCode.addInstancePostProcessor(generatedMethod.toMethodReference());
|
||||
};
|
||||
List<BeanRegistrationAotContribution> aotContributions = Collections
|
||||
.singletonList(aotContribution);
|
||||
|
@ -167,8 +166,7 @@ class BeanDefinitionMethodGeneratorTests {
|
|||
.addParameter(RegisteredBean.class, "registeredBean")
|
||||
.addParameter(TestBean.class, "testBean")
|
||||
.returns(TestBean.class).addCode("return new $T($S);", TestBean.class, "postprocessed"));
|
||||
beanRegistrationCode.addInstancePostProcessor(MethodReference.ofStatic(
|
||||
beanRegistrationCode.getClassName(), generatedMethod.getName()));
|
||||
beanRegistrationCode.addInstancePostProcessor(generatedMethod.toMethodReference());
|
||||
};
|
||||
List<BeanRegistrationAotContribution> aotContributions = Collections
|
||||
.singletonList(aotContribution);
|
||||
|
|
|
@ -33,7 +33,6 @@ import org.apache.commons.logging.LogFactory;
|
|||
import org.springframework.aop.framework.autoproxy.AutoProxyUtils;
|
||||
import org.springframework.aot.generate.GeneratedMethod;
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.aot.generate.MethodReference;
|
||||
import org.springframework.aot.hint.ResourceHints;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
import org.springframework.beans.PropertyValues;
|
||||
|
@ -536,7 +535,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
|||
.add("addImportAwareBeanPostProcessors", method ->
|
||||
generateAddPostProcessorMethod(method, mappings));
|
||||
beanFactoryInitializationCode
|
||||
.addInitializer(MethodReference.of(generatedMethod.getName()));
|
||||
.addInitializer(generatedMethod.toMethodReference());
|
||||
ResourceHints hints = generationContext.getRuntimeHints().resources();
|
||||
mappings.forEach(
|
||||
(target, from) -> hints.registerType(TypeReference.of(from)));
|
||||
|
|
|
@ -55,7 +55,7 @@ public final class GeneratedClass {
|
|||
GeneratedClass(ClassName name, Consumer<TypeSpec.Builder> type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.methods = new GeneratedMethods(this::generateSequencedMethodName);
|
||||
this.methods = new GeneratedMethods(name, this::generateSequencedMethodName);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@ package org.springframework.aot.generate;
|
|||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.lang.model.element.Modifier;
|
||||
|
||||
import org.springframework.javapoet.ClassName;
|
||||
import org.springframework.javapoet.MethodSpec;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
@ -25,11 +28,14 @@ import org.springframework.util.Assert;
|
|||
* A generated method.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.0
|
||||
* @see GeneratedMethods
|
||||
*/
|
||||
public final class GeneratedMethod {
|
||||
|
||||
private final ClassName className;
|
||||
|
||||
private final String name;
|
||||
|
||||
private final MethodSpec methodSpec;
|
||||
|
@ -39,12 +45,14 @@ public final class GeneratedMethod {
|
|||
* Create a new {@link GeneratedMethod} instance with the given name. This
|
||||
* constructor is package-private since names should only be generated via
|
||||
* {@link GeneratedMethods}.
|
||||
* @param className the declaring class of the method
|
||||
* @param name the generated method name
|
||||
* @param method consumer to generate the method
|
||||
*/
|
||||
GeneratedMethod(String name, Consumer<MethodSpec.Builder> method) {
|
||||
GeneratedMethod(ClassName className, String name, Consumer<MethodSpec.Builder> method) {
|
||||
this.className = className;
|
||||
this.name = name;
|
||||
MethodSpec.Builder builder = MethodSpec.methodBuilder(getName());
|
||||
MethodSpec.Builder builder = MethodSpec.methodBuilder(this.name);
|
||||
method.accept(builder);
|
||||
this.methodSpec = builder.build();
|
||||
Assert.state(this.name.equals(this.methodSpec.name),
|
||||
|
@ -60,6 +68,16 @@ public final class GeneratedMethod {
|
|||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link MethodReference} to this generated method.
|
||||
* @return a method reference
|
||||
*/
|
||||
public MethodReference toMethodReference() {
|
||||
return (this.methodSpec.modifiers.contains(Modifier.STATIC)
|
||||
? MethodReference.ofStatic(this.className, this.name)
|
||||
: MethodReference.of(this.className, this.name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link MethodSpec} for this generated method.
|
||||
* @return the method spec
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.function.Consumer;
|
|||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.javapoet.ClassName;
|
||||
import org.springframework.javapoet.MethodSpec;
|
||||
import org.springframework.javapoet.MethodSpec.Builder;
|
||||
import org.springframework.util.Assert;
|
||||
|
@ -30,11 +31,14 @@ import org.springframework.util.Assert;
|
|||
* A managed collection of generated methods.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.0
|
||||
* @see GeneratedMethod
|
||||
*/
|
||||
public class GeneratedMethods {
|
||||
|
||||
private final ClassName className;
|
||||
|
||||
private final Function<MethodName, String> methodNameGenerator;
|
||||
|
||||
private final MethodName prefix;
|
||||
|
@ -44,18 +48,22 @@ public class GeneratedMethods {
|
|||
/**
|
||||
* Create a new {@link GeneratedMethods} using the specified method name
|
||||
* generator.
|
||||
* @param className the declaring class name
|
||||
* @param methodNameGenerator the method name generator
|
||||
*/
|
||||
GeneratedMethods(Function<MethodName, String> methodNameGenerator) {
|
||||
GeneratedMethods(ClassName className, Function<MethodName, String> methodNameGenerator) {
|
||||
Assert.notNull(className, "'className' must not be null");
|
||||
Assert.notNull(methodNameGenerator, "'methodNameGenerator' must not be null");
|
||||
this.className = className;
|
||||
this.methodNameGenerator = methodNameGenerator;
|
||||
this.prefix = MethodName.NONE;
|
||||
this.generatedMethods = new ArrayList<>();
|
||||
}
|
||||
|
||||
private GeneratedMethods(Function<MethodName, String> methodNameGenerator,
|
||||
private GeneratedMethods(ClassName className, Function<MethodName, String> methodNameGenerator,
|
||||
MethodName prefix, List<GeneratedMethod> generatedMethods) {
|
||||
|
||||
this.className = className;
|
||||
this.methodNameGenerator = methodNameGenerator;
|
||||
this.prefix = prefix;
|
||||
this.generatedMethods = generatedMethods;
|
||||
|
@ -82,7 +90,7 @@ public class GeneratedMethods {
|
|||
Assert.notNull(suggestedNameParts, "'suggestedNameParts' must not be null");
|
||||
Assert.notNull(method, "'method' must not be null");
|
||||
String generatedName = this.methodNameGenerator.apply(this.prefix.and(suggestedNameParts));
|
||||
GeneratedMethod generatedMethod = new GeneratedMethod(generatedName, method);
|
||||
GeneratedMethod generatedMethod = new GeneratedMethod(this.className, generatedName, method);
|
||||
this.generatedMethods.add(generatedMethod);
|
||||
return generatedMethod;
|
||||
}
|
||||
|
@ -90,7 +98,8 @@ public class GeneratedMethods {
|
|||
|
||||
public GeneratedMethods withPrefix(String prefix) {
|
||||
Assert.notNull(prefix, "'prefix' must not be null");
|
||||
return new GeneratedMethods(this.methodNameGenerator, this.prefix.and(prefix), this.generatedMethods);
|
||||
return new GeneratedMethods(this.className, this.methodNameGenerator,
|
||||
this.prefix.and(prefix), this.generatedMethods);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,8 +18,12 @@ package org.springframework.aot.generate;
|
|||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.lang.model.element.Modifier;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.javapoet.ClassName;
|
||||
import org.springframework.javapoet.CodeBlock;
|
||||
import org.springframework.javapoet.MethodSpec;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
@ -29,30 +33,55 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
|||
* Tests for {@link GeneratedMethod}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class GeneratedMethodTests {
|
||||
|
||||
private static final Consumer<MethodSpec.Builder> methodSpecCustomizer = method -> {};
|
||||
private static final ClassName TEST_CLASS_NAME = ClassName.get("com.example", "Test");
|
||||
|
||||
private static final Consumer<MethodSpec.Builder> emptyMethod = method -> {};
|
||||
|
||||
private static final String NAME = "spring";
|
||||
|
||||
@Test
|
||||
void getNameReturnsName() {
|
||||
GeneratedMethod generatedMethod = new GeneratedMethod(NAME, methodSpecCustomizer);
|
||||
GeneratedMethod generatedMethod = new GeneratedMethod(TEST_CLASS_NAME, NAME, emptyMethod);
|
||||
assertThat(generatedMethod.getName()).isSameAs(NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateMethodSpecReturnsMethodSpec() {
|
||||
GeneratedMethod generatedMethod = new GeneratedMethod(NAME, method -> method.addJavadoc("Test"));
|
||||
GeneratedMethod generatedMethod = create(method -> method.addJavadoc("Test"));
|
||||
assertThat(generatedMethod.getMethodSpec().javadoc).asString().contains("Test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateMethodSpecWhenMethodNameIsChangedThrowsException() {
|
||||
assertThatIllegalStateException().isThrownBy(() ->
|
||||
new GeneratedMethod(NAME, method -> method.setName("badname")).getMethodSpec())
|
||||
.withMessage("'method' consumer must not change the generated method name");
|
||||
create(method -> method.setName("badname")).getMethodSpec())
|
||||
.withMessage("'method' consumer must not change the generated method name");
|
||||
}
|
||||
|
||||
@Test
|
||||
void toMethodReferenceWithInstanceMethod() {
|
||||
GeneratedMethod generatedMethod = create(emptyMethod);
|
||||
MethodReference methodReference = generatedMethod.toMethodReference();
|
||||
assertThat(methodReference).isNotNull();
|
||||
assertThat(methodReference.toInvokeCodeBlock("test"))
|
||||
.isEqualTo(CodeBlock.of("test.spring()"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void toMethodReferenceWithStaticMethod() {
|
||||
GeneratedMethod generatedMethod = create(method -> method.addModifiers(Modifier.STATIC));
|
||||
MethodReference methodReference = generatedMethod.toMethodReference();
|
||||
assertThat(methodReference).isNotNull();
|
||||
assertThat(methodReference.toInvokeCodeBlock())
|
||||
.isEqualTo(CodeBlock.of("com.example.Test.spring()"));
|
||||
}
|
||||
|
||||
private GeneratedMethod create(Consumer<MethodSpec.Builder> method) {
|
||||
return new GeneratedMethod(TEST_CLASS_NAME, NAME, method);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.function.Function;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.javapoet.ClassName;
|
||||
import org.springframework.javapoet.MethodSpec;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
@ -32,38 +33,49 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
|||
* Tests for {@link GeneratedMethods}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class GeneratedMethodsTests {
|
||||
|
||||
private static final ClassName TEST_CLASS_NAME = ClassName.get("com.example", "Test");
|
||||
|
||||
private static final Consumer<MethodSpec.Builder> methodSpecCustomizer = method -> {};
|
||||
|
||||
private final GeneratedMethods methods = new GeneratedMethods(MethodName::toString);
|
||||
private final GeneratedMethods methods = new GeneratedMethods(TEST_CLASS_NAME, MethodName::toString);
|
||||
|
||||
@Test
|
||||
void createWhenClassNameIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() ->
|
||||
new GeneratedMethods(null, MethodName::toString))
|
||||
.withMessage("'className' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWhenMethodNameGeneratorIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new GeneratedMethods(null))
|
||||
assertThatIllegalArgumentException().isThrownBy(() ->
|
||||
new GeneratedMethods(TEST_CLASS_NAME, null))
|
||||
.withMessage("'methodNameGenerator' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWithExistingGeneratorUsesGenerator() {
|
||||
Function<MethodName, String> generator = name -> "__" + name.toString();
|
||||
GeneratedMethods methods = new GeneratedMethods(generator);
|
||||
GeneratedMethods methods = new GeneratedMethods(TEST_CLASS_NAME, generator);
|
||||
assertThat(methods.add("test", methodSpecCustomizer).getName()).hasToString("__test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void addWithStringNameWhenSuggestedMethodIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() ->
|
||||
this.methods.add((String) null, methodSpecCustomizer))
|
||||
.withMessage("'suggestedName' must not be null");
|
||||
this.methods.add((String) null, methodSpecCustomizer))
|
||||
.withMessage("'suggestedName' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void addWithStringNameWhenMethodIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() ->
|
||||
this.methods.add("test", null))
|
||||
.withMessage("'method' must not be null");
|
||||
this.methods.add("test", null))
|
||||
.withMessage("'method' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -71,7 +83,7 @@ class GeneratedMethodsTests {
|
|||
this.methods.add("springBeans", methodSpecCustomizer);
|
||||
this.methods.add("springContext", methodSpecCustomizer);
|
||||
assertThat(this.methods.stream().map(GeneratedMethod::getName).map(Object::toString))
|
||||
.containsExactly("springBeans", "springContext");
|
||||
.containsExactly("springBeans", "springContext");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -99,7 +99,7 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr
|
|||
List.class, toCodeBlock(persistenceManagedTypes.getManagedPackages()));
|
||||
method.addStatement("return $T.of($L, $L)", beanType, "managedClassNames", "managedPackages");
|
||||
});
|
||||
return CodeBlock.of("() -> $T.$L()", beanRegistrationCode.getClassName(), generatedMethod.getName());
|
||||
return generatedMethod.toMethodReference().toCodeBlock();
|
||||
}
|
||||
|
||||
private CodeBlock toCodeBlock(List<String> values) {
|
||||
|
|
|
@ -43,7 +43,6 @@ import org.springframework.aot.generate.GeneratedClass;
|
|||
import org.springframework.aot.generate.GeneratedMethod;
|
||||
import org.springframework.aot.generate.GeneratedMethods;
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.aot.generate.MethodReference;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.PropertyValues;
|
||||
|
@ -797,8 +796,7 @@ public class PersistenceAnnotationBeanPostProcessor implements InstantiationAwar
|
|||
method.returns(this.target);
|
||||
method.addCode(generateMethodCode(generationContext.getRuntimeHints(), generatedClass.getMethods()));
|
||||
});
|
||||
beanRegistrationCode.addInstancePostProcessor(MethodReference
|
||||
.ofStatic(generatedClass.getName(), generatedMethod.getName()));
|
||||
beanRegistrationCode.addInstancePostProcessor(generatedMethod.toMethodReference());
|
||||
}
|
||||
|
||||
private CodeBlock generateMethodCode(RuntimeHints hints, GeneratedMethods generatedMethods) {
|
||||
|
|
Loading…
Reference in New Issue