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:
parent
dfae8effa8
commit
b3ceb0f625
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* 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.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.lang.model.element.Modifier;
|
||||
|
||||
import org.springframework.javapoet.CodeBlock;
|
||||
import org.springframework.javapoet.JavaFile;
|
||||
import org.springframework.javapoet.MethodSpec;
|
||||
import org.springframework.javapoet.TypeSpec;
|
||||
|
||||
/**
|
||||
* A code snippet using tabs indentation that is fully processed by JavaPoet so
|
||||
* that imports are resolved.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.0
|
||||
*/
|
||||
public final class CodeSnippet {
|
||||
|
||||
private static final String START_SNIPPET = "// start-snippet\n";
|
||||
|
||||
private static final String END_SNIPPET = "// end-snippet";
|
||||
|
||||
private final String fileContent;
|
||||
|
||||
private final String snippet;
|
||||
|
||||
|
||||
CodeSnippet(String fileContent, String snippet) {
|
||||
this.fileContent = fileContent;
|
||||
this.snippet = snippet;
|
||||
}
|
||||
|
||||
|
||||
String getFileContent() {
|
||||
return this.fileContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rendered code snippet.
|
||||
* @return a code snippet where imports have been resolved
|
||||
*/
|
||||
public String getSnippet() {
|
||||
return this.snippet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify if an import statement for the specified type is present.
|
||||
* @param type the type to check
|
||||
* @return true if this type has an import statement, false otherwise
|
||||
*/
|
||||
public boolean hasImport(Class<?> type) {
|
||||
return hasImport(type.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify if an import statement for the specified class name is present.
|
||||
* @param className the name of the class to check
|
||||
* @return true if this type has an import statement, false otherwise
|
||||
*/
|
||||
public boolean hasImport(String className) {
|
||||
return getFileContent().lines().anyMatch(candidate ->
|
||||
candidate.equals(String.format("import %s;", className)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link CodeSnippet} where the specified number of indentations
|
||||
* have been removed.
|
||||
* @param indent the number of indent to remove
|
||||
* @return a CodeSnippet instance with the number of indentations removed
|
||||
*/
|
||||
public CodeSnippet removeIndent(int indent) {
|
||||
return new CodeSnippet(this.fileContent, this.snippet.lines().map(line ->
|
||||
removeIndent(line, indent)).collect(Collectors.joining("\n")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link CodeSnippet} using the specified code.
|
||||
* @param code the code snippet
|
||||
* @return a {@link CodeSnippet} instance
|
||||
*/
|
||||
public static CodeSnippet of(CodeBlock code) {
|
||||
return new Builder().build(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the specified code and return a fully-processed code snippet
|
||||
* as a String.
|
||||
* @param code a consumer to use to generate the code snippet
|
||||
* @return a resolved code snippet
|
||||
*/
|
||||
public static String process(Consumer<CodeBlock.Builder> code) {
|
||||
CodeBlock.Builder body = CodeBlock.builder();
|
||||
code.accept(body);
|
||||
return process(body.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the specified {@link CodeBlock code} and return a
|
||||
* fully-processed code snippet as a String.
|
||||
* @param code the code snippet
|
||||
* @return a resolved code snippet
|
||||
*/
|
||||
public static String process(CodeBlock code) {
|
||||
return of(code).getSnippet();
|
||||
}
|
||||
|
||||
private String removeIndent(String line, int indent) {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
if (line.startsWith("\t")) {
|
||||
line = line.substring(1);
|
||||
}
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
private static final class Builder {
|
||||
|
||||
private static final String INDENT = "\t";
|
||||
|
||||
private static final String SNIPPET_INDENT = INDENT + INDENT;
|
||||
|
||||
public CodeSnippet build(CodeBlock code) {
|
||||
MethodSpec.Builder method = MethodSpec.methodBuilder("test")
|
||||
.addModifiers(Modifier.PUBLIC);
|
||||
CodeBlock.Builder body = CodeBlock.builder();
|
||||
body.add(START_SNIPPET);
|
||||
body.add(code);
|
||||
body.add(END_SNIPPET);
|
||||
method.addCode(body.build());
|
||||
String fileContent = write(createTestJavaFile(method.build()));
|
||||
String snippet = isolateGeneratedContent(fileContent);
|
||||
return new CodeSnippet(fileContent, snippet);
|
||||
}
|
||||
|
||||
private String isolateGeneratedContent(String javaFile) {
|
||||
int start = javaFile.indexOf(START_SNIPPET);
|
||||
String tmp = javaFile.substring(start + START_SNIPPET.length());
|
||||
int end = tmp.indexOf(END_SNIPPET);
|
||||
tmp = tmp.substring(0, end);
|
||||
// Remove indent
|
||||
return tmp.lines().map(line -> {
|
||||
if (!line.startsWith(SNIPPET_INDENT)) {
|
||||
throw new IllegalStateException("Missing indent for " + line);
|
||||
}
|
||||
return line.substring(SNIPPET_INDENT.length());
|
||||
}).collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
private JavaFile createTestJavaFile(MethodSpec method) {
|
||||
return JavaFile.builder("example", TypeSpec.classBuilder("Test")
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addMethod(method).build()).indent(INDENT).build();
|
||||
}
|
||||
|
||||
private String write(JavaFile file) {
|
||||
try {
|
||||
StringWriter out = new StringWriter();
|
||||
file.writeTo(out);
|
||||
return out.toString();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException("Failed to write " + file, ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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 java.util.function.Consumer;
|
||||
|
||||
import org.springframework.javapoet.CodeBlock;
|
||||
import org.springframework.javapoet.CodeBlock.Builder;
|
||||
|
||||
|
||||
/**
|
||||
* A {@link CodeBlock} wrapper for joining multiple blocks.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.0
|
||||
*/
|
||||
public class MultiCodeBlock {
|
||||
|
||||
private final List<CodeBlock> codeBlocks = new ArrayList<>();
|
||||
|
||||
|
||||
/**
|
||||
* Add the specified {@link CodeBlock}.
|
||||
* @param code the code block to add
|
||||
*/
|
||||
public void add(CodeBlock code) {
|
||||
if (code.isEmpty()) {
|
||||
throw new IllegalArgumentException("Could not add empty CodeBlock");
|
||||
}
|
||||
this.codeBlocks.add(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a {@link CodeBlock} using the specified callback.
|
||||
* @param code the callback to use
|
||||
*/
|
||||
public void add(Consumer<Builder> code) {
|
||||
Builder builder = CodeBlock.builder();
|
||||
code.accept(builder);
|
||||
add(builder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a code block using the specified formatted String and the specified
|
||||
* arguments.
|
||||
* @param code the code
|
||||
* @param arguments the arguments
|
||||
* @see Builder#add(String, Object...)
|
||||
*/
|
||||
public void add(String code, Object... arguments) {
|
||||
add(CodeBlock.of(code, arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link CodeBlock} that joins the different blocks registered in
|
||||
* this instance with the specified delimiter.
|
||||
* @param delimiter the delimiter to use (not {@literal null})
|
||||
* @return a {@link CodeBlock} joining the blocks of this instance with the
|
||||
* specified {@code delimiter}
|
||||
* @see CodeBlock#join(Iterable, String)
|
||||
*/
|
||||
public CodeBlock join(String delimiter) {
|
||||
return CodeBlock.join(this.codeBlocks, delimiter);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* 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 java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.javapoet.CodeBlock;
|
||||
import org.springframework.javapoet.CodeBlock.Builder;
|
||||
|
||||
|
||||
/**
|
||||
* A {@link CodeBlock} wrapper for multiple statements.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.0
|
||||
*/
|
||||
public final class MultiStatement {
|
||||
|
||||
private final List<Statement> statements = new ArrayList<>();
|
||||
|
||||
|
||||
/**
|
||||
* Specify if this instance is empty.
|
||||
* @return {@code true} if no statement is registered, {@code false} otherwise
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return this.statements.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the specified {@link CodeBlock codeblock} rendered as-is.
|
||||
* @param codeBlock the code block to add
|
||||
* @see #addStatement(CodeBlock) to add a code block that represents
|
||||
* a statement
|
||||
*/
|
||||
public void add(CodeBlock codeBlock) {
|
||||
this.statements.add(Statement.of(codeBlock));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a {@link CodeBlock} rendered as-is using the specified callback.
|
||||
* @param code the callback to use
|
||||
* @see #addStatement(CodeBlock) to add a code block that represents
|
||||
* a statement
|
||||
*/
|
||||
public void add(Consumer<Builder> code) {
|
||||
CodeBlock.Builder builder = CodeBlock.builder();
|
||||
code.accept(builder);
|
||||
add(builder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a statement.
|
||||
* @param statement the statement to add
|
||||
*/
|
||||
public void addStatement(CodeBlock statement) {
|
||||
this.statements.add(Statement.ofStatement(statement));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a statement using the specified callback.
|
||||
* @param code the callback to use
|
||||
*/
|
||||
public void addStatement(Consumer<Builder> code) {
|
||||
CodeBlock.Builder builder = CodeBlock.builder();
|
||||
code.accept(builder);
|
||||
addStatement(builder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a statement using the specified formatted String and the specified
|
||||
* arguments.
|
||||
* @param code the code of the statement
|
||||
* @param args the arguments for placeholders
|
||||
* @see CodeBlock#of(String, Object...)
|
||||
*/
|
||||
public void addStatement(String code, Object... args) {
|
||||
addStatement(CodeBlock.of(code, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the statements produced from the {@code itemGenerator} applied on the specified
|
||||
* items.
|
||||
* @param items the items to handle, each item is represented as a statement
|
||||
* @param itemGenerator the item generator
|
||||
* @param <T> the type of the item
|
||||
*/
|
||||
public <T> void addAll(Iterable<T> items, Function<T, CodeBlock> itemGenerator) {
|
||||
items.forEach(element -> addStatement(itemGenerator.apply(element)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
Builder code = CodeBlock.builder();
|
||||
for (int i = 0; i < this.statements.size(); i++) {
|
||||
Statement statement = this.statements.get(i);
|
||||
statement.contribute(code, this.isMulti(), i == this.statements.size() - 1);
|
||||
}
|
||||
return code.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link CodeBlock} that applies all the {@code statements} of this
|
||||
* instance in the context of a lambda.
|
||||
* @param lambda the context of the lambda, must end with {@code ->}
|
||||
* @return the lambda body
|
||||
*/
|
||||
public CodeBlock toCodeBlock(CodeBlock lambda) {
|
||||
Builder code = CodeBlock.builder();
|
||||
code.add(lambda);
|
||||
if (isMulti()) {
|
||||
code.beginControlFlow("");
|
||||
}
|
||||
else {
|
||||
code.add(" ");
|
||||
}
|
||||
code.add(toCodeBlock());
|
||||
if (isMulti()) {
|
||||
code.add("\n").unindent().add("}");
|
||||
}
|
||||
return code.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link CodeBlock} that applies all the {@code statements} of this
|
||||
* instance in the context of a lambda.
|
||||
* @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));
|
||||
}
|
||||
|
||||
private boolean isMulti() {
|
||||
return this.statements.size() > 1;
|
||||
}
|
||||
|
||||
|
||||
private static class Statement {
|
||||
|
||||
private final CodeBlock codeBlock;
|
||||
|
||||
private final boolean addStatementTermination;
|
||||
|
||||
Statement(CodeBlock codeBlock, boolean addStatementTermination) {
|
||||
this.codeBlock = codeBlock;
|
||||
this.addStatementTermination = addStatementTermination;
|
||||
}
|
||||
|
||||
void contribute(CodeBlock.Builder code, boolean multi, boolean isLastStatement) {
|
||||
code.add(this.codeBlock);
|
||||
if (this.addStatementTermination) {
|
||||
if (!isLastStatement) {
|
||||
code.add(";\n");
|
||||
}
|
||||
else if (multi) {
|
||||
code.add(";");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Statement ofStatement(CodeBlock codeBlock) {
|
||||
return new Statement(codeBlock, true);
|
||||
}
|
||||
|
||||
static Statement of(CodeBlock codeBlock) {
|
||||
return new Statement(codeBlock, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/**
|
||||
* Support classes for JavaPoet usage.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.javapoet.support;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
||||
|
|
@ -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\";",
|
||||
"}");
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue