Add support for annotating parameters

Closes gh-1002
This commit is contained in:
Stephane Nicoll 2023-06-12 10:57:35 +02:00
parent eb618d5dd7
commit 6ca2dcc5cd
10 changed files with 299 additions and 65 deletions

View File

@ -55,7 +55,7 @@ class GroovyProjectGenerationDefaultContributorsConfiguration {
return (typeDeclaration) -> typeDeclaration.addMethodDeclaration(GroovyMethodDeclaration.method("main")
.modifiers(Modifier.PUBLIC | Modifier.STATIC)
.returning("void")
.parameters(new Parameter("java.lang.String[]", "args"))
.parameters(Parameter.of("args", String[].class))
.body(CodeBlock.ofStatement("$T.run($L, args)", "org.springframework.boot.SpringApplication",
typeDeclaration.getName())));
}
@ -91,7 +91,7 @@ class GroovyProjectGenerationDefaultContributorsConfiguration {
.modifiers(Modifier.PROTECTED)
.returning("org.springframework.boot.builder.SpringApplicationBuilder")
.parameters(
new Parameter("org.springframework.boot.builder.SpringApplicationBuilder", "application"))
Parameter.of("application", "org.springframework.boot.builder.SpringApplicationBuilder"))
.body(CodeBlock.ofStatement("application.sources($L)", description.getApplicationName()));
configure.annotations().add(ClassName.of(Override.class));
typeDeclaration.addMethodDeclaration(configure);

View File

@ -49,7 +49,7 @@ class JavaProjectGenerationDefaultContributorsConfiguration {
typeDeclaration.addMethodDeclaration(JavaMethodDeclaration.method("main")
.modifiers(Modifier.PUBLIC | Modifier.STATIC)
.returning("void")
.parameters(new Parameter("java.lang.String[]", "args"))
.parameters(Parameter.of("args", String[].class))
.body(CodeBlock.ofStatement("$T.run($L.class, args)", "org.springframework.boot.SpringApplication",
typeDeclaration.getName())));
};
@ -82,7 +82,7 @@ class JavaProjectGenerationDefaultContributorsConfiguration {
.modifiers(Modifier.PROTECTED)
.returning("org.springframework.boot.builder.SpringApplicationBuilder")
.parameters(
new Parameter("org.springframework.boot.builder.SpringApplicationBuilder", "application"))
Parameter.of("application", "org.springframework.boot.builder.SpringApplicationBuilder"))
.body(CodeBlock.ofStatement("return application.sources($L.class)",
description.getApplicationName()));
configure.annotations().add(ClassName.of(Override.class));

View File

@ -95,7 +95,7 @@ class KotlinProjectGenerationDefaultContributorsConfiguration {
MainCompilationUnitCustomizer<KotlinTypeDeclaration, KotlinCompilationUnit> mainFunctionContributor(
ProjectDescription description) {
return (compilationUnit) -> compilationUnit.addTopLevelFunction(KotlinFunctionDeclaration.function("main")
.parameters(new Parameter("Array<String>", "args"))
.parameters(Parameter.of("args", "Array<String>"))
.body(CodeBlock.ofStatement("$T<$L>(*args)", "org.springframework.boot.runApplication",
description.getApplicationName())));
}
@ -117,7 +117,7 @@ class KotlinProjectGenerationDefaultContributorsConfiguration {
.modifiers(KotlinModifier.OVERRIDE)
.returning("org.springframework.boot.builder.SpringApplicationBuilder")
.parameters(
new Parameter("org.springframework.boot.builder.SpringApplicationBuilder", "application"))
Parameter.of("application", "org.springframework.boot.builder.SpringApplicationBuilder"))
.body(CodeBlock.ofStatement("return application.sources($L::class.java)",
description.getApplicationName()));
typeDeclaration.addFunctionDeclaration(configure);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2023 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.
@ -16,28 +16,167 @@
package io.spring.initializr.generator.language;
import java.util.function.Consumer;
/**
* A parameter, typically of a method or function.
*
* @author Andy Wilkinson
* @author Stephane Nicoll
*/
public class Parameter {
private final String type;
public class Parameter implements Annotatable {
private final String name;
private final String type;
private final AnnotationContainer annotations;
/**
* Create a parameter with the specified type and name.
* @param type the type of the annotation
* @param name the name of the annotation
* @deprecated in favor of {@link #of(String, String)}
*/
@Deprecated(since = "0.20.0", forRemoval = true)
public Parameter(String type, String name) {
this.type = type;
this.name = name;
this(new Builder(name).type(type));
}
public String getType() {
return this.type;
private Parameter(Builder builder) {
this.name = builder.name;
this.type = builder.type;
this.annotations = builder.annotations.deepCopy();
}
/**
* Create a parameter with the specified name and type.
* @param name the name of the parameter
* @param type the type
* @return a parameter
*/
public static Parameter of(String name, String type) {
return new Builder(name).type(type).build();
}
/**
* Create a parameter with the specified name and {@link ClassName type}.
* @param name the name of the parameter
* @param type the type
* @return a parameter
*/
public static Parameter of(String name, ClassName type) {
return new Builder(name).type(type).build();
}
/**
* Create a parameter with the specified name and {@link Class type}.
* @param name the name of the parameter
* @param type the type
* @return a parameter
*/
public static Parameter of(String name, Class<?> type) {
return new Builder(name).type(type).build();
}
/**
* Initialize a builder for a parameter with the specified name.
* @param name the name of the parameter
* @return a builder to further configure the parameter
*/
public static Builder builder(String name) {
return new Builder(name);
}
/**
* Return the name of the parameter.
* @return the name
*/
public String getName() {
return this.name;
}
/**
* Return the typ of the parameter.
* @return the type
*/
public String getType() {
return this.type;
}
@Override
public AnnotationContainer annotations() {
return this.annotations;
}
/**
* Builder for creating a {@link Parameter}.
*/
public static class Builder {
private final String name;
private String type;
private final AnnotationContainer annotations = new AnnotationContainer();
Builder(String name) {
this.name = name;
}
/**
* Specify the {@link ClassName type} of the parameter.
* @param type the type
* @return this for method chaining
*/
public Builder type(ClassName type) {
return type(type.getName());
}
/**
* Specify the {@link Class type} of the parameter.
* @param type the type
* @return this for method chaining
*/
public Builder type(Class<?> type) {
return type(type.getCanonicalName());
}
/**
* Specify the type of the parameter.
* @param type the type
* @return this for method chaining
*/
public Builder type(String type) {
this.type = type;
return this;
}
/**
* Annotate the parameter with the specified annotation.
* @param className the class of the annotation
* @return this for method chaining
*/
public Builder annotate(ClassName className) {
return annotate(className, null);
}
/**
* Annotate the parameter with the specified annotation, customized by the
* specified consumer.
* @param className the class of the annotation
* @param annotation a consumer of the builder
* @return this for method chaining
*/
public Builder annotate(ClassName className, Consumer<Annotation.Builder> annotation) {
this.annotations.add(className, annotation);
return this;
}
public Parameter build() {
return new Parameter(this);
}
}
}

View File

@ -24,6 +24,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@ -144,13 +145,17 @@ public class GroovySourceCodeWriter implements SourceCodeWriter<GroovySourceCode
}
}
private void writeAnnotations(IndentingWriter writer, Annotatable annotatable) {
private void writeAnnotations(IndentingWriter writer, Annotatable annotatable, Runnable separator) {
annotatable.annotations().values().forEach((annotation) -> {
annotation.write(writer, FORMATTING_OPTIONS);
writer.println();
separator.run();
});
}
private void writeAnnotations(IndentingWriter writer, Annotatable annotatable) {
writeAnnotations(writer, annotatable, writer::println);
}
private void writeFieldDeclaration(IndentingWriter writer, GroovyFieldDeclaration fieldDeclaration) {
writeAnnotations(writer, fieldDeclaration);
writeModifiers(writer, FIELD_MODIFIERS, fieldDeclaration.getModifiers());
@ -169,12 +174,7 @@ public class GroovySourceCodeWriter implements SourceCodeWriter<GroovySourceCode
writeAnnotations(writer, methodDeclaration);
writeModifiers(writer, METHOD_MODIFIERS, methodDeclaration.getModifiers());
writer.print(getUnqualifiedName(methodDeclaration.getReturnType()) + " " + methodDeclaration.getName() + "(");
List<Parameter> parameters = methodDeclaration.getParameters();
if (!parameters.isEmpty()) {
writer.print(parameters.stream()
.map((parameter) -> getUnqualifiedName(parameter.getType()) + " " + parameter.getName())
.collect(Collectors.joining(", ")));
}
writeParameters(writer, methodDeclaration.getParameters());
writer.println(") {");
writer.indented(() -> {
methodDeclaration.getCode().write(writer, FORMATTING_OPTIONS);
@ -184,6 +184,21 @@ public class GroovySourceCodeWriter implements SourceCodeWriter<GroovySourceCode
writer.println();
}
private void writeParameters(IndentingWriter writer, List<Parameter> parameters) {
if (parameters.isEmpty()) {
return;
}
Iterator<Parameter> it = parameters.iterator();
while (it.hasNext()) {
Parameter parameter = it.next();
writeAnnotations(writer, parameter, () -> writer.print(" "));
writer.print(getUnqualifiedName(parameter.getType()) + " " + parameter.getName());
if (it.hasNext()) {
writer.print(", ");
}
}
}
@SuppressWarnings("removal")
private void writeStatements(IndentingWriter writer, GroovyMethodDeclaration methodDeclaration) {
List<GroovyStatement> statements = methodDeclaration.getStatements();
@ -234,8 +249,10 @@ public class GroovySourceCodeWriter implements SourceCodeWriter<GroovySourceCode
for (GroovyMethodDeclaration methodDeclaration : typeDeclaration.getMethodDeclarations()) {
imports.add(methodDeclaration.getReturnType());
imports.addAll(appendImports(methodDeclaration.annotations().values(), Annotation::getImports));
imports.addAll(appendImports(methodDeclaration.getParameters(),
(parameter) -> Collections.singletonList(parameter.getType())));
for (Parameter parameter : methodDeclaration.getParameters()) {
imports.add(parameter.getType());
imports.addAll(appendImports(parameter.annotations().values(), Annotation::getImports));
}
imports.addAll(methodDeclaration.getCode().getImports());
determineImportsFromStatements(imports, methodDeclaration);
}

View File

@ -23,6 +23,7 @@ import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@ -112,7 +113,7 @@ public class JavaSourceCodeWriter implements SourceCodeWriter<JavaSourceCode> {
writer.println();
}
for (JavaTypeDeclaration type : compilationUnit.getTypeDeclarations()) {
writeAnnotations(writer, type);
writeAnnotations(writer, type, writer::println);
writeModifiers(writer, TYPE_MODIFIERS, type.getModifiers());
writer.print("class " + type.getName());
if (type.getExtends() != null) {
@ -141,13 +142,17 @@ public class JavaSourceCodeWriter implements SourceCodeWriter<JavaSourceCode> {
}
}
private void writeAnnotations(IndentingWriter writer, Annotatable annotatable) {
private void writeAnnotations(IndentingWriter writer, Annotatable annotatable, Runnable separator) {
annotatable.annotations().values().forEach((annotation) -> {
annotation.write(writer, CodeBlock.JAVA_FORMATTING_OPTIONS);
writer.println();
separator.run();
});
}
private void writeAnnotations(IndentingWriter writer, Annotatable annotatable) {
writeAnnotations(writer, annotatable, writer::println);
}
private void writeFieldDeclaration(IndentingWriter writer, JavaFieldDeclaration fieldDeclaration) {
writeAnnotations(writer, fieldDeclaration);
writeModifiers(writer, FIELD_MODIFIERS, fieldDeclaration.getModifiers());
@ -166,12 +171,7 @@ public class JavaSourceCodeWriter implements SourceCodeWriter<JavaSourceCode> {
writeAnnotations(writer, methodDeclaration);
writeModifiers(writer, METHOD_MODIFIERS, methodDeclaration.getModifiers());
writer.print(getUnqualifiedName(methodDeclaration.getReturnType()) + " " + methodDeclaration.getName() + "(");
List<Parameter> parameters = methodDeclaration.getParameters();
if (!parameters.isEmpty()) {
writer.print(parameters.stream()
.map((parameter) -> getUnqualifiedName(parameter.getType()) + " " + parameter.getName())
.collect(Collectors.joining(", ")));
}
writeParameters(writer, methodDeclaration.getParameters());
writer.println(") {");
writer.indented(() -> {
methodDeclaration.getCode().write(writer, CodeBlock.JAVA_FORMATTING_OPTIONS);
@ -181,6 +181,21 @@ public class JavaSourceCodeWriter implements SourceCodeWriter<JavaSourceCode> {
writer.println();
}
private void writeParameters(IndentingWriter writer, List<Parameter> parameters) {
if (parameters.isEmpty()) {
return;
}
Iterator<Parameter> it = parameters.iterator();
while (it.hasNext()) {
Parameter parameter = it.next();
writeAnnotations(writer, parameter, () -> writer.print(" "));
writer.print(getUnqualifiedName(parameter.getType()) + " " + parameter.getName());
if (it.hasNext()) {
writer.print(", ");
}
}
}
@SuppressWarnings("removal")
private void writeJavaStatements(IndentingWriter writer, JavaMethodDeclaration methodDeclaration) {
List<JavaStatement> statements = methodDeclaration.getStatements();
@ -233,8 +248,10 @@ public class JavaSourceCodeWriter implements SourceCodeWriter<JavaSourceCode> {
for (JavaMethodDeclaration methodDeclaration : typeDeclaration.getMethodDeclarations()) {
imports.add(methodDeclaration.getReturnType());
imports.addAll(appendImports(methodDeclaration.annotations().values(), Annotation::getImports));
imports.addAll(appendImports(methodDeclaration.getParameters(),
(parameter) -> Collections.singletonList(parameter.getType())));
for (Parameter parameter : methodDeclaration.getParameters()) {
imports.add(parameter.getType());
imports.addAll(appendImports(parameter.annotations().values(), Annotation::getImports));
}
determineImportsFromStatements(imports, methodDeclaration);
imports.addAll(methodDeclaration.getCode().getImports());
}

View File

@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
@ -156,9 +157,7 @@ public class KotlinSourceCodeWriter implements SourceCodeWriter<KotlinSourceCode
private void writeAccessor(IndentingWriter writer, String accessorName,
KotlinPropertyDeclaration.Accessor accessor) {
if (!accessor.annotations().isEmpty()) {
accessor.annotations().values().forEach((annotation) -> writeAnnotation(writer, annotation, false));
}
writeAnnotations(writer, accessor, () -> writer.print(" "));
writer.print(accessorName);
if (!accessor.isEmptyBody()) {
writer.print("() = ");
@ -177,12 +176,7 @@ public class KotlinSourceCodeWriter implements SourceCodeWriter<KotlinSourceCode
writeModifiers(writer, functionDeclaration.getModifiers());
writer.print("fun ");
writer.print(functionDeclaration.getName() + "(");
List<Parameter> parameters = functionDeclaration.getParameters();
if (!parameters.isEmpty()) {
writer.print(parameters.stream()
.map((parameter) -> parameter.getName() + ": " + getUnqualifiedName(parameter.getType()))
.collect(Collectors.joining(", ")));
}
writeParameters(writer, functionDeclaration.getParameters());
writer.print(")");
if (functionDeclaration.getReturnType() != null) {
writer.print(": " + getUnqualifiedName(functionDeclaration.getReturnType()));
@ -195,6 +189,21 @@ public class KotlinSourceCodeWriter implements SourceCodeWriter<KotlinSourceCode
writer.println("}");
}
private void writeParameters(IndentingWriter writer, List<Parameter> parameters) {
if (parameters.isEmpty()) {
return;
}
Iterator<Parameter> it = parameters.iterator();
while (it.hasNext()) {
Parameter parameter = it.next();
writeAnnotations(writer, parameter, () -> writer.print(" "));
writer.print(parameter.getName() + ": " + getUnqualifiedName(parameter.getType()));
if (it.hasNext()) {
writer.print(", ");
}
}
}
@SuppressWarnings("removal")
private void writeStatements(IndentingWriter writer, KotlinFunctionDeclaration functionDeclaration) {
List<KotlinStatement> statements = functionDeclaration.getStatements();
@ -210,18 +219,15 @@ public class KotlinSourceCodeWriter implements SourceCodeWriter<KotlinSourceCode
}
}
private void writeAnnotations(IndentingWriter writer, Annotatable annotatable) {
annotatable.annotations().values().forEach((annotation) -> writeAnnotation(writer, annotation, true));
private void writeAnnotations(IndentingWriter writer, Annotatable annotatable, Runnable separator) {
annotatable.annotations().values().forEach((annotation) -> {
annotation.write(writer, FORMATTING_OPTIONS);
separator.run();
});
}
private void writeAnnotation(IndentingWriter writer, Annotation annotation, boolean newLine) {
annotation.write(writer, FORMATTING_OPTIONS);
if (newLine) {
writer.println();
}
else {
writer.print(" ");
}
private void writeAnnotations(IndentingWriter writer, Annotatable annotatable) {
writeAnnotations(writer, annotatable, writer::println);
}
private void writeModifiers(IndentingWriter writer, List<KotlinModifier> declaredModifiers) {
@ -287,8 +293,10 @@ public class KotlinSourceCodeWriter implements SourceCodeWriter<KotlinSourceCode
Set<String> imports = new LinkedHashSet<>();
imports.add(functionDeclaration.getReturnType());
imports.addAll(appendImports(functionDeclaration.annotations().values(), Annotation::getImports));
imports.addAll(appendImports(functionDeclaration.getParameters(),
(parameter) -> Collections.singleton(parameter.getType())));
for (Parameter parameter : functionDeclaration.getParameters()) {
imports.add(parameter.getType());
imports.addAll(appendImports(parameter.annotations().values(), Annotation::getImports));
}
imports.addAll(functionDeclaration.getCode().getImports());
imports.addAll(appendImports(
getKotlinExpressions(functionDeclaration).filter(KotlinFunctionInvocation.class::isInstance)

View File

@ -117,7 +117,7 @@ class GroovySourceCodeWriterTests {
GroovyTypeDeclaration test = compilationUnit.createTypeDeclaration("Test");
test.addMethodDeclaration(GroovyMethodDeclaration.method("trim")
.returning("java.lang.String")
.parameters(new Parameter("java.lang.String", "value"))
.parameters(Parameter.of("value", String.class))
.body(CodeBlock.ofStatement("value.trim()")));
List<String> lines = writeSingleType(sourceCode, "com/example/Test.groovy");
assertThat(lines).containsExactly("package com.example", "", "class Test {", "",
@ -133,7 +133,7 @@ class GroovySourceCodeWriterTests {
GroovyTypeDeclaration test = compilationUnit.createTypeDeclaration("Test");
test.addMethodDeclaration(GroovyMethodDeclaration.method("trim")
.returning("java.lang.String")
.parameters(new Parameter("java.lang.String", "value"))
.parameters(Parameter.of("value", String.class))
.body(new GroovyReturnStatement(new GroovyMethodInvocation("value", "trim"))));
List<String> lines = writeSingleType(sourceCode, "com/example/Test.groovy");
assertThat(lines).containsExactly("package com.example", "", "class Test {", "",
@ -163,7 +163,7 @@ class GroovySourceCodeWriterTests {
test.addMethodDeclaration(GroovyMethodDeclaration.method("main")
.modifiers(Modifier.PUBLIC | Modifier.STATIC)
.returning("void")
.parameters(new Parameter("java.lang.String[]", "args"))
.parameters(Parameter.of("args", String[].class))
.body(CodeBlock.ofStatement("$T.run($L, args)", "org.springframework.boot.SpringApplication", "Test")));
List<String> lines = writeSingleType(sourceCode, "com/example/Test.groovy");
assertThat(lines).containsExactly("package com.example", "",
@ -311,6 +311,24 @@ class GroovySourceCodeWriterTests {
"class Test {", "", " @TestAnnotation", " void something() {", " }", "", "}");
}
@Test
void methodWithParameterAnnotation() throws IOException {
GroovySourceCode sourceCode = new GroovySourceCode();
GroovyCompilationUnit compilationUnit = sourceCode.createCompilationUnit("com.example", "Test");
GroovyTypeDeclaration test = compilationUnit.createTypeDeclaration("Test");
test.addMethodDeclaration(GroovyMethodDeclaration.method("something")
.returning("void")
.parameters(Parameter.builder("service")
.type(ClassName.of("com.example.another.MyService"))
.annotate(ClassName.of("com.example.stereotype.Service"))
.build())
.body(CodeBlock.of("")));
List<String> lines = writeSingleType(sourceCode, "com/example/Test.groovy");
assertThat(lines).containsExactly("package com.example", "", "import com.example.another.MyService",
"import com.example.stereotype.Service", "", "class Test {", "",
" void something(@Service MyService service) {", " }", "", "}");
}
private List<String> writeSingleType(GroovySourceCode sourceCode, String location) throws IOException {
Path source = writeSourceCode(sourceCode).resolve(location);
try (InputStream stream = Files.newInputStream(source)) {

View File

@ -117,7 +117,7 @@ class JavaSourceCodeWriterTests {
test.addMethodDeclaration(JavaMethodDeclaration.method("trim")
.returning("java.lang.String")
.modifiers(Modifier.PUBLIC)
.parameters(new Parameter("java.lang.String", "value"))
.parameters(Parameter.of("value", String.class))
.body(CodeBlock.ofStatement("return value.trim()")));
List<String> lines = writeSingleType(sourceCode, "com/example/Test.java");
assertThat(lines).containsExactly("package com.example;", "", "class Test {", "",
@ -134,7 +134,7 @@ class JavaSourceCodeWriterTests {
test.addMethodDeclaration(JavaMethodDeclaration.method("trim")
.returning("java.lang.String")
.modifiers(Modifier.PUBLIC)
.parameters(new Parameter("java.lang.String", "value"))
.parameters(Parameter.of("value", String.class))
.body(new JavaReturnStatement(new JavaMethodInvocation("value", "trim"))));
List<String> lines = writeSingleType(sourceCode, "com/example/Test.java");
assertThat(lines).containsExactly("package com.example;", "", "class Test {", "",
@ -258,7 +258,7 @@ class JavaSourceCodeWriterTests {
test.addMethodDeclaration(JavaMethodDeclaration.method("main")
.modifiers(Modifier.PUBLIC | Modifier.STATIC)
.returning("void")
.parameters(new Parameter("java.lang.String[]", "args"))
.parameters(Parameter.of("args", String[].class))
.body(CodeBlock.ofStatement("$T.run($L.class, args)", "org.springframework.boot.SpringApplication",
"Test")));
List<String> lines = writeSingleType(sourceCode, "com/example/Test.java");
@ -339,6 +339,24 @@ class JavaSourceCodeWriterTests {
"class Test {", "", " @TestAnnotation", " void something() {", " }", "", "}");
}
@Test
void methodWithParameterAnnotation() throws IOException {
JavaSourceCode sourceCode = new JavaSourceCode();
JavaCompilationUnit compilationUnit = sourceCode.createCompilationUnit("com.example", "Test");
JavaTypeDeclaration test = compilationUnit.createTypeDeclaration("Test");
test.addMethodDeclaration(JavaMethodDeclaration.method("something")
.returning("void")
.parameters(Parameter.builder("service")
.type(ClassName.of("com.example.another.MyService"))
.annotate(ClassName.of("com.example.stereotype.Service"))
.build())
.body(CodeBlock.of("")));
List<String> lines = writeSingleType(sourceCode, "com/example/Test.java");
assertThat(lines).containsExactly("package com.example;", "", "import com.example.another.MyService;",
"import com.example.stereotype.Service;", "", "class Test {", "",
" void something(@Service MyService service) {", " }", "", "}");
}
private List<String> writeSingleType(JavaSourceCode sourceCode, String location) throws IOException {
Path source = writeSourceCode(sourceCode).resolve(location);
try (InputStream stream = Files.newInputStream(source)) {

View File

@ -116,7 +116,7 @@ class KotlinSourceCodeWriterTests {
KotlinTypeDeclaration test = compilationUnit.createTypeDeclaration("Test");
test.addFunctionDeclaration(KotlinFunctionDeclaration.function("reverse")
.returning("java.lang.String")
.parameters(new Parameter("java.lang.String", "echo"))
.parameters(Parameter.of("echo", String.class))
.body(CodeBlock.ofStatement("return echo.reversed()")));
List<String> lines = writeSingleType(sourceCode, "com/example/Test.kt");
assertThat(lines).containsExactly("package com.example", "", "class Test {", "",
@ -132,7 +132,7 @@ class KotlinSourceCodeWriterTests {
KotlinTypeDeclaration test = compilationUnit.createTypeDeclaration("Test");
test.addFunctionDeclaration(KotlinFunctionDeclaration.function("reverse")
.returning("java.lang.String")
.parameters(new Parameter("java.lang.String", "echo"))
.parameters(Parameter.of("echo", String.class))
.body(new KotlinReturnStatement(new KotlinFunctionInvocation("echo", "reversed"))));
List<String> lines = writeSingleType(sourceCode, "com/example/Test.kt");
assertThat(lines).containsExactly("package com.example", "", "class Test {", "",
@ -320,7 +320,7 @@ class KotlinSourceCodeWriterTests {
KotlinTypeDeclaration test = compilationUnit.createTypeDeclaration("Test");
test.annotations().add(ClassName.of("org.springframework.boot.autoconfigure.SpringBootApplication"));
compilationUnit.addTopLevelFunction(KotlinFunctionDeclaration.function("main")
.parameters(new Parameter("Array<String>", "args"))
.parameters(Parameter.of("args", "Array<String>"))
.body(CodeBlock.ofStatement("$T<$L>(*args)", "org.springframework.boot.runApplication", "Test")));
List<String> lines = writeSingleType(sourceCode, "com/example/Test.kt");
assertThat(lines).containsExactly("package com.example", "",
@ -392,6 +392,23 @@ class KotlinSourceCodeWriterTests {
"class Test {", "", " @TestAnnotation", " fun something() {", " }", "", "}");
}
@Test
void functionWithParameterAnnotation() throws IOException {
KotlinSourceCode sourceCode = new KotlinSourceCode();
KotlinCompilationUnit compilationUnit = sourceCode.createCompilationUnit("com.example", "Test");
KotlinTypeDeclaration test = compilationUnit.createTypeDeclaration("Test");
test.addFunctionDeclaration(KotlinFunctionDeclaration.function("something")
.parameters(Parameter.builder("service")
.type(ClassName.of("com.example.another.MyService"))
.annotate(ClassName.of("com.example.stereotype.Service"))
.build())
.body(CodeBlock.of("")));
List<String> lines = writeSingleType(sourceCode, "com/example/Test.kt");
assertThat(lines).containsExactly("package com.example", "", "import com.example.another.MyService",
"import com.example.stereotype.Service", "", "class Test {", "",
" fun something(@Service service: MyService) {", " }", "", "}");
}
private List<String> writeSingleType(KotlinSourceCode sourceCode, String location) throws IOException {
Path source = writeSourceCode(sourceCode).resolve(location);
try (InputStream stream = Files.newInputStream(source)) {