Refine MultiStatement#toClodeBlock

Closes gh-28363
This commit is contained in:
Stephane Nicoll 2022-04-21 15:22:41 +02:00
parent ccb66247ce
commit 10d254983f
5 changed files with 65 additions and 25 deletions

View File

@ -345,7 +345,7 @@ public class BeanRegistrationBeanFactoryContribution implements BeanFactoryContr
}
code.add("\n").indent().indent();
code.add(".instanceSupplier(");
code.add(instanceStatements.toCodeBlock());
code.add(instanceStatements.toLambdaBody());
code.add(")").unindent().unindent();
handleBeanDefinitionMetadata(code);
}
@ -421,7 +421,7 @@ public class BeanRegistrationBeanFactoryContribution implements BeanFactoryContr
if (statements.isEmpty()) {
return;
}
code.add(statements.toCodeBlock(".customize((" + bdVariable + ") ->"));
code.add(statements.toLambdaBody(".customize((" + bdVariable + ") ->"));
code.add(")");
}

View File

@ -43,7 +43,7 @@ class AutowiredAnnotationBeanInstantiationContributionTests {
@Test
void contributeWithPackageProtectedFieldInjection() {
CodeContribution contribution = contribute(PackageProtectedFieldInjectionSample.class);
assertThat(CodeSnippet.process(contribution.statements().toCodeBlock())).isEqualTo("""
assertThat(CodeSnippet.process(contribution.statements().toLambdaBody())).isEqualTo("""
instanceContext.field("environment")
.invoke(beanFactory, (attributes) -> bean.environment = attributes.get(0))""");
assertThat(contribution.runtimeHints().reflection().typeHints()).singleElement().satisfies(typeHint -> {
@ -61,7 +61,7 @@ class AutowiredAnnotationBeanInstantiationContributionTests {
@Test
void contributeWithPrivateFieldInjection() {
CodeContribution contribution = contribute(PrivateFieldInjectionSample.class);
assertThat(CodeSnippet.process(contribution.statements().toCodeBlock())).isEqualTo("""
assertThat(CodeSnippet.process(contribution.statements().toLambdaBody())).isEqualTo("""
instanceContext.field("environment")
.invoke(beanFactory, (attributes) -> {
Field environmentField = ReflectionUtils.findField(AutowiredAnnotationBeanInstantiationContributionTests.PrivateFieldInjectionSample.class, "environment");
@ -82,7 +82,7 @@ class AutowiredAnnotationBeanInstantiationContributionTests {
@Test
void contributeWithPublicMethodInjection() {
CodeContribution contribution = contribute(PublicMethodInjectionSample.class);
assertThat(CodeSnippet.process(contribution.statements().toCodeBlock())).isEqualTo("""
assertThat(CodeSnippet.process(contribution.statements().toLambdaBody())).isEqualTo("""
instanceContext.method("setTestBean", TestBean.class)
.invoke(beanFactory, (attributes) -> bean.setTestBean(attributes.get(0)))""");
assertThat(contribution.runtimeHints().reflection().typeHints()).singleElement().satisfies(typeHint -> {
@ -98,7 +98,7 @@ class AutowiredAnnotationBeanInstantiationContributionTests {
@Test
void contributeWithInjectionPoints() {
CodeContribution contribution = contribute(ResourceInjectionBean.class);
assertThat(CodeSnippet.process(contribution.statements().toCodeBlock())).isEqualTo("""
assertThat(CodeSnippet.process(contribution.statements().toLambdaBody())).isEqualTo("""
instanceContext.field("testBean")
.resolve(beanFactory, false).ifResolved((attributes) -> {
Field testBeanField = ReflectionUtils.findField(AutowiredAnnotationBeanPostProcessorTests.ResourceInjectionBean.class, "testBean");

View File

@ -209,7 +209,7 @@ class DefaultBeanInstantiationGeneratorTests {
}
private String code(CodeContribution contribution) {
return CodeSnippet.process(contribution.statements().toCodeBlock());
return CodeSnippet.process(contribution.statements().toLambdaBody());
}
@Nullable

View File

@ -116,13 +116,24 @@ public final class MultiStatement {
return this;
}
/**
* Return a {@link CodeBlock} that applies all the {@code statements} of
* this instance.
* @return the code block
*/
public CodeBlock toCodeBlock() {
Builder code = CodeBlock.builder();
this.statements.forEach(statement -> statement.add(code));
return code.build();
}
/**
* Return a {@link CodeBlock} that applies all the {@code statements} of this
* instance. If only one statement is available, it is not completed using the
* {@code ;} termination so that it can be used in the context of a lambda.
* @return the statement(s)
*/
public CodeBlock toCodeBlock() {
public CodeBlock toLambdaBody() {
Builder code = CodeBlock.builder();
for (int i = 0; i < this.statements.size(); i++) {
Statement statement = this.statements.get(i);
@ -137,7 +148,7 @@ public final class MultiStatement {
* @param lambda the context of the lambda, must end with {@code ->}
* @return the lambda body
*/
public CodeBlock toCodeBlock(CodeBlock lambda) {
public CodeBlock toLambdaBody(CodeBlock lambda) {
Builder code = CodeBlock.builder();
code.add(lambda);
if (isMulti()) {
@ -146,7 +157,7 @@ public final class MultiStatement {
else {
code.add(" ");
}
code.add(toCodeBlock());
code.add(toLambdaBody());
if (isMulti()) {
code.add("\n").unindent().add("}");
}
@ -159,8 +170,8 @@ public final class MultiStatement {
* @param lambda the context of the lambda, must end with {@code ->}
* @return the lambda body
*/
public CodeBlock toCodeBlock(String lambda) {
return toCodeBlock(CodeBlock.of(lambda));
public CodeBlock toLambdaBody(String lambda) {
return toLambdaBody(CodeBlock.of(lambda));
}
private boolean isMulti() {
@ -179,6 +190,13 @@ public final class MultiStatement {
this.addStatementTermination = addStatementTermination;
}
void add(CodeBlock.Builder code) {
code.add(this.codeBlock);
if (this.addStatementTermination) {
code.add(";\n");
}
}
void contribute(CodeBlock.Builder code, boolean multi, boolean isLastStatement) {
code.add(this.codeBlock);
if (this.addStatementTermination) {

View File

@ -44,48 +44,70 @@ class MultiStatementTests {
}
@Test
void singleStatement() {
void singleStatementCodeBlock() {
MultiStatement statements = new MultiStatement();
statements.addStatement("field.method($S)", "hello");
CodeBlock codeBlock = statements.toCodeBlock();
assertThat(codeBlock.toString()).isEqualTo("""
field.method("hello");
""");
}
@Test
void multiStatementsCodeBlock() {
MultiStatement statements = new MultiStatement();
statements.addStatement("field.method($S)", "hello");
statements.addStatement("field.another($S)", "test");
CodeBlock codeBlock = statements.toCodeBlock();
assertThat(codeBlock.toString()).isEqualTo("""
field.method("hello");
field.another("test");
""");
}
@Test
void singleStatementLambdaBody() {
MultiStatement statements = new MultiStatement();
statements.addStatement("field.method($S)", "hello");
CodeBlock codeBlock = statements.toLambdaBody();
assertThat(codeBlock.toString()).isEqualTo("field.method(\"hello\")");
}
@Test
void singleStatementWithCallback() {
void singleStatementWithCallbackLambdaBody() {
MultiStatement statements = new MultiStatement();
statements.addStatement(code -> code.add("field.method($S)", "hello"));
CodeBlock codeBlock = statements.toCodeBlock();
CodeBlock codeBlock = statements.toLambdaBody();
assertThat(codeBlock.toString()).isEqualTo("field.method(\"hello\")");
}
@Test
void singleStatementWithCodeBlock() {
void singleStatementWithCodeBlockLambdaBody() {
MultiStatement statements = new MultiStatement();
statements.addStatement(CodeBlock.of("field.method($S)", "hello"));
CodeBlock codeBlock = statements.toCodeBlock();
CodeBlock codeBlock = statements.toLambdaBody();
assertThat(codeBlock.toString()).isEqualTo("field.method(\"hello\")");
}
@Test
void multiStatements() {
void multiStatementsLambdaBody() {
MultiStatement statements = new MultiStatement();
statements.addStatement("field.method($S)", "hello");
statements.addStatement("field.anotherMethod($S)", "hello");
CodeBlock codeBlock = statements.toCodeBlock();
CodeBlock codeBlock = statements.toLambdaBody();
assertThat(codeBlock.toString()).isEqualTo("""
field.method("hello");
field.anotherMethod("hello");""");
}
@Test
void multiStatementsWithCodeBlockRenderedAsIs() {
void multiStatementsWithCodeBlockRenderedAsIsLambdaBody() {
MultiStatement statements = new MultiStatement();
statements.addStatement("field.method($S)", "hello");
statements.add(CodeBlock.of(("// Hello\n")));
statements.add(code -> code.add("// World\n"));
statements.addStatement("field.anotherMethod($S)", "hello");
CodeBlock codeBlock = statements.toCodeBlock();
CodeBlock codeBlock = statements.toLambdaBody();
assertThat(codeBlock.toString()).isEqualTo("""
field.method("hello");
// Hello
@ -97,7 +119,7 @@ class MultiStatementTests {
void singleStatementWithLambda() {
MultiStatement statements = new MultiStatement();
statements.addStatement("field.method($S)", "hello");
CodeBlock codeBlock = statements.toCodeBlock(CodeBlock.of("() ->"));
CodeBlock codeBlock = statements.toLambdaBody(CodeBlock.of("() ->"));
assertThat(codeBlock.toString()).isEqualTo("() -> field.method(\"hello\")");
}
@ -106,7 +128,7 @@ class MultiStatementTests {
MultiStatement statements = new MultiStatement();
statements.addStatement("field.method($S)", "hello");
statements.addStatement("field.anotherMethod($S)", "hello");
CodeBlock codeBlock = statements.toCodeBlock(CodeBlock.of("() ->"));
CodeBlock codeBlock = statements.toLambdaBody(CodeBlock.of("() ->"));
assertThat(codeBlock.toString().lines()).containsExactly(
"() -> {",
" field.method(\"hello\");",
@ -115,11 +137,11 @@ class MultiStatementTests {
}
@Test
void multiStatementsWithAddAll() {
void multiStatementsWithAddAllAndLambda() {
MultiStatement statements = new MultiStatement();
statements.addAll(List.of(0, 1, 2),
index -> CodeBlock.of("field[$L] = $S", index, "hello"));
CodeBlock codeBlock = statements.toCodeBlock("() ->");
CodeBlock codeBlock = statements.toLambdaBody("() ->");
assertThat(codeBlock.toString().lines()).containsExactly(
"() -> {",
" field[0] = \"hello\";",