Add core JavaPoet utilities

This commit adds utilities that facilitate code generation patterns
used by the AOT engine.

Closes gh-28028
This commit is contained in:
Stephane Nicoll
2022-02-10 14:57:37 +01:00
parent dfae8effa8
commit b3ceb0f625
7 changed files with 740 additions and 0 deletions
@@ -0,0 +1,75 @@
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.javapoet.support;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.javapoet.CodeBlock;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link CodeSnippet}.
*
* @author Stephane Nicoll
*/
class CodeSnippetTests {
@Test
void snippetUsesTabs() {
CodeBlock.Builder code = CodeBlock.builder();
code.beginControlFlow("if (condition)");
code.addStatement("bean.doThis()");
code.endControlFlow();
CodeSnippet codeSnippet = CodeSnippet.of(code.build());
assertThat(codeSnippet.getSnippet()).isEqualTo("""
if (condition) {
bean.doThis();
}
""");
}
@Test
void snippetResolvesImports() {
CodeSnippet codeSnippet = CodeSnippet.of(
CodeBlock.of("$T list = new $T<>()", List.class, ArrayList.class));
assertThat(codeSnippet.getSnippet()).isEqualTo("List list = new ArrayList<>()");
assertThat(codeSnippet.hasImport(List.class)).isTrue();
assertThat(codeSnippet.hasImport(ArrayList.class)).isTrue();
}
@Test
void removeIndent() {
CodeBlock.Builder code = CodeBlock.builder();
code.beginControlFlow("if (condition)");
code.addStatement("doStuff()");
code.endControlFlow();
CodeSnippet snippet = CodeSnippet.of(code.build());
assertThat(snippet.getSnippet().lines()).contains("\tdoStuff();");
assertThat(snippet.removeIndent(1).getSnippet().lines()).contains("doStuff();");
}
@Test
void processProvidesSnippet() {
assertThat(CodeSnippet.process(code -> code.add("$T list;", List.class)))
.isEqualTo("List list;");
}
}
@@ -0,0 +1,61 @@
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.javapoet.support;
import org.junit.jupiter.api.Test;
import org.springframework.javapoet.CodeBlock;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link MultiCodeBlock}.
*
* @author Stephane Nicoll
*/
class MultiCodeBlockTests {
@Test
void joinWithNoElement() {
MultiCodeBlock multi = new MultiCodeBlock();
assertThat(multi.join(", ").isEmpty()).isTrue();
}
@Test
void joinWithEmptyElement() {
MultiCodeBlock multi = new MultiCodeBlock();
assertThatIllegalArgumentException().isThrownBy(() -> multi.add(CodeBlock.builder().build()));
}
@Test
void joinWithSingleElement() {
MultiCodeBlock multi = new MultiCodeBlock();
multi.add(CodeBlock.of("$S", "Hello"));
assertThat(multi.join(", ")).hasToString("\"Hello\"");
}
@Test
void joinWithSeveralElement() {
MultiCodeBlock multi = new MultiCodeBlock();
multi.add(CodeBlock.of("$S", "Hello"));
multi.add(code -> code.add("42"));
multi.add("null");
assertThat(multi.join(", ")).hasToString("\"Hello\", 42, null");
}
}
@@ -0,0 +1,131 @@
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.javapoet.support;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.javapoet.CodeBlock;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link MultiStatement}.
*
* @author Stephane Nicoll
*/
class MultiStatementTests {
@Test
void isEmptyWithNoStatement() {
assertThat(new MultiStatement().isEmpty()).isTrue();
}
@Test
void isEmptyWithStatement() {
MultiStatement statements = new MultiStatement();
statements.addStatement(CodeBlock.of("int i = 0"));
assertThat(statements.isEmpty()).isFalse();
}
@Test
void singleStatement() {
MultiStatement statements = new MultiStatement();
statements.addStatement("field.method($S)", "hello");
CodeBlock codeBlock = statements.toCodeBlock();
assertThat(codeBlock.toString()).isEqualTo("field.method(\"hello\")");
}
@Test
void singleStatementWithCallback() {
MultiStatement statements = new MultiStatement();
statements.addStatement(code -> code.add("field.method($S)", "hello"));
CodeBlock codeBlock = statements.toCodeBlock();
assertThat(codeBlock.toString()).isEqualTo("field.method(\"hello\")");
}
@Test
void singleStatementWithCodeBlock() {
MultiStatement statements = new MultiStatement();
statements.addStatement(CodeBlock.of("field.method($S)", "hello"));
CodeBlock codeBlock = statements.toCodeBlock();
assertThat(codeBlock.toString()).isEqualTo("field.method(\"hello\")");
}
@Test
void multiStatements() {
MultiStatement statements = new MultiStatement();
statements.addStatement("field.method($S)", "hello");
statements.addStatement("field.anotherMethod($S)", "hello");
CodeBlock codeBlock = statements.toCodeBlock();
assertThat(codeBlock.toString()).isEqualTo("""
field.method("hello");
field.anotherMethod("hello");""");
}
@Test
void multiStatementsWithCodeBlockRenderedAsIs() {
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();
assertThat(codeBlock.toString()).isEqualTo("""
field.method("hello");
// Hello
// World
field.anotherMethod("hello");""");
}
@Test
void singleStatementWithLambda() {
MultiStatement statements = new MultiStatement();
statements.addStatement("field.method($S)", "hello");
CodeBlock codeBlock = statements.toCodeBlock(CodeBlock.of("() ->"));
assertThat(codeBlock.toString()).isEqualTo("() -> field.method(\"hello\")");
}
@Test
void multiStatementsWithLambda() {
MultiStatement statements = new MultiStatement();
statements.addStatement("field.method($S)", "hello");
statements.addStatement("field.anotherMethod($S)", "hello");
CodeBlock codeBlock = statements.toCodeBlock(CodeBlock.of("() ->"));
assertThat(codeBlock.toString().lines()).containsExactly(
"() -> {",
" field.method(\"hello\");",
" field.anotherMethod(\"hello\");",
"}");
}
@Test
void multiStatementsWithAddAll() {
MultiStatement statements = new MultiStatement();
statements.addAll(List.of(0, 1, 2),
index -> CodeBlock.of("field[$L] = $S", index, "hello"));
CodeBlock codeBlock = statements.toCodeBlock("() ->");
assertThat(codeBlock.toString().lines()).containsExactly(
"() -> {",
" field[0] = \"hello\";",
" field[1] = \"hello\";",
" field[2] = \"hello\";",
"}");
}
}