Add support for generating methods

Add `GeneratedMethods` and `GeneratedMethod` support classes which
can be used during code generation to generation additional methods
that will ultimately be included in a `JavaFile`.

See gh-28414
This commit is contained in:
Phillip Webb
2022-04-13 18:21:50 -07:00
parent 16456342f5
commit 55d7f7a014
7 changed files with 574 additions and 0 deletions
@@ -0,0 +1,72 @@
/*
* 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.aot.generate;
import javax.lang.model.element.Modifier;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
* Tests for {@link GeneratedMethod}.
*
* @author Phillip Webb
*/
class GeneratedMethodTests {
private static final String NAME = "spring";
@Test
void getNameReturnsName() {
GeneratedMethod method = new GeneratedMethod(NAME);
assertThat(method.getName()).isSameAs(NAME);
}
@Test
void getSpecReturnsSpec() {
GeneratedMethod method = new GeneratedMethod(NAME);
method.using(builder -> builder.addJavadoc("Test"));
assertThat(method.getSpec().javadoc.toString()).contains("Test");
}
@Test
void getSpecReturnsSpecWhenNoSpecDefinedThrowsException() {
GeneratedMethod method = new GeneratedMethod(NAME);
assertThatIllegalStateException().isThrownBy(() -> method.getSpec())
.withMessage("Method 'spring' has no method spec defined");
}
@Test
void usingAddsSpec() {
GeneratedMethod method = new GeneratedMethod(NAME);
method.using(builder -> builder.addModifiers(Modifier.PUBLIC));
assertThat(method.getSpec().toString())
.isEqualToIgnoringNewLines("public void spring() {}");
}
@Test
void usingWhenBuilderChanagesNameThrowsException() {
GeneratedMethod method = new GeneratedMethod(NAME);
assertThatIllegalArgumentException()
.isThrownBy(() -> method.using(builder -> builder.setName("badname")))
.withMessage("'spec' must use the generated name \"spring\"");
}
}
@@ -0,0 +1,100 @@
/*
* 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.aot.generate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.javapoet.MethodSpec;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
* Tests for {@link GeneratedMethods}.
*
* @author Phillip Webb
*/
class GeneratedMethodsTests {
private final GeneratedMethods methods = new GeneratedMethods();
@Test
void createWhenMethodNameGeneratorIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> new GeneratedMethods(null))
.withMessage("'methodNameGenerator' must not be null");
}
@Test
void createWithExistingGeneratorUsesGenerator() {
MethodNameGenerator generator = new MethodNameGenerator();
generator.generateMethodName("test");
GeneratedMethods methods = new GeneratedMethods(generator);
assertThat(methods.add("test").getName()).hasToString("test1");
}
@Test
void addAddsMethod() {
this.methods.add("spring", "beans").using(this::build);
this.methods.add("spring", "context").using(this::build);
assertThat(
this.methods.stream().map(GeneratedMethod::getName).map(Object::toString))
.containsExactly("springBeans", "springContext");
}
@Test
void doWithMethodSpecsAcceptsMethodSpecs() {
this.methods.add("spring", "beans").using(this::build);
this.methods.add("spring", "context").using(this::build);
List<String> names = new ArrayList<>();
this.methods.doWithMethodSpecs(spec -> names.add(spec.name));
assertThat(names).containsExactly("springBeans", "springContext");
}
@Test
void doWithMethodSpecsWhenMethodHasNotHadSpecDefinedThrowsException() {
this.methods.add("spring");
assertThatIllegalStateException()
.isThrownBy(() -> this.methods.doWithMethodSpecs(spec -> {
})).withMessage("Method 'spring' has no method spec defined");
}
@Test
void iteratorIteratesMethods() {
this.methods.add("spring", "beans").using(this::build);
this.methods.add("spring", "context").using(this::build);
Iterator<GeneratedMethod> iterator = this.methods.iterator();
assertThat(iterator.next().getName()).hasToString("springBeans");
assertThat(iterator.next().getName()).hasToString("springContext");
assertThat(iterator.hasNext()).isFalse();
}
@Test
void streamStreamsMethods() {
this.methods.add("spring", "beans").using(this::build);
this.methods.add("spring", "context").using(this::build);
assertThat(this.methods.stream()).hasSize(2);
}
private void build(MethodSpec.Builder builder) {
}
}
@@ -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.aot.generate;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests {@link MethodGeneratorWithName}.
*
* @author Phillip Webb
* @since 6.0
*/
class MethodGeneratorWithNameTests {
private final GeneratedMethods generatedMethods = new GeneratedMethods();
@Test
void withNameWhenGeneratingGetMethod() {
GeneratedMethod generateMethod = generatedMethods.withName("my", "bean")
.generateMethod("get", "test");
assertThat(generateMethod.getName()).hasToString("getMyBeanTest");
}
@Test
void withNameWhenGeneratingSetMethod() {
GeneratedMethod generateMethod = generatedMethods.withName("my", "bean")
.generateMethod("set", "test");
assertThat(generateMethod.getName()).hasToString("setMyBeanTest");
}
@Test
void withNameWhenGeneratingIsMethod() {
GeneratedMethod generateMethod = generatedMethods.withName("my", "bean")
.generateMethod("is", "test");
assertThat(generateMethod.getName()).hasToString("isMyBeanTest");
}
@Test
void withNameWhenGeneratingOtherMethod() {
GeneratedMethod generateMethod = generatedMethods.withName("my", "bean")
.generateMethod("test");
assertThat(generateMethod.getName()).hasToString("myBeanTest");
}
}