Harmonize use of generate

This commit harmonizes the use of the "generate" keyword for anything
related to code generation. Previously, there was a mix of "generate"
and "write."

See gh-28047
This commit is contained in:
Stephane Nicoll 2022-03-04 10:00:57 +01:00
parent ea19b92deb
commit 97986b368a
6 changed files with 151 additions and 149 deletions

View File

@ -838,7 +838,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
boolean isRequired = isRequired(element); boolean isRequired = isRequired(element);
Member member = element.getMember(); Member member = element.getMember();
analyzeMember(contribution, member); analyzeMember(contribution, member);
contribution.statements().addStatement(this.generator.writeInjection(member, isRequired)); contribution.statements().addStatement(this.generator.generateInjection(member, isRequired));
}); });
} }

View File

@ -43,7 +43,7 @@ import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
/** /**
* Support for writing parameters. * Support for generating parameters.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 6.0 * @since 6.0
@ -52,16 +52,16 @@ public final class BeanParameterGenerator {
private final ResolvableTypeGenerator typeGenerator = new ResolvableTypeGenerator(); private final ResolvableTypeGenerator typeGenerator = new ResolvableTypeGenerator();
private final BiConsumer<BeanDefinition, Builder> innerBeanDefinitionWriter; private final BiConsumer<BeanDefinition, Builder> innerBeanDefinitionGenerator;
/** /**
* Create an instance with the callback to use to write an inner bean * Create an instance with the callback to use to generate an inner bean
* definition. * definition.
* @param innerBeanDefinitionWriter the inner bean definition writer * @param innerBeanDefinitionGenerator the inner bean definition generator
*/ */
public BeanParameterGenerator(BiConsumer<BeanDefinition, Builder> innerBeanDefinitionWriter) { public BeanParameterGenerator(BiConsumer<BeanDefinition, Builder> innerBeanDefinitionGenerator) {
this.innerBeanDefinitionWriter = innerBeanDefinitionWriter; this.innerBeanDefinitionGenerator = innerBeanDefinitionGenerator;
} }
/** /**
@ -75,39 +75,39 @@ public final class BeanParameterGenerator {
/** /**
* Write the specified parameter {@code value}. * Generate the specified parameter {@code value}.
* @param value the value of the parameter * @param value the value of the parameter
* @return the value of the parameter * @return the value of the parameter
*/ */
public CodeBlock writeParameterValue(@Nullable Object value) { public CodeBlock generateParameterValue(@Nullable Object value) {
return writeParameterValue(value, () -> ResolvableType.forInstance(value)); return generateParameterValue(value, () -> ResolvableType.forInstance(value));
} }
/** /**
* Write the specified parameter {@code value}. * Generate the specified parameter {@code value}.
* @param value the value of the parameter * @param value the value of the parameter
* @param parameterType the type of the parameter * @param parameterType the type of the parameter
* @return the value of the parameter * @return the value of the parameter
*/ */
public CodeBlock writeParameterValue(@Nullable Object value, Supplier<ResolvableType> parameterType) { public CodeBlock generateParameterValue(@Nullable Object value, Supplier<ResolvableType> parameterType) {
Builder code = CodeBlock.builder(); Builder code = CodeBlock.builder();
writeParameterValue(code, value, parameterType); generateParameterValue(code, value, parameterType);
return code.build(); return code.build();
} }
/** /**
* Write the parameter types of the specified {@link Executable}. * Generate the parameter types of the specified {@link Executable}.
* @param executable the executable * @param executable the executable
* @return the parameter types of the executable as a comma separated list * @return the parameter types of the executable as a comma separated list
*/ */
public CodeBlock writeExecutableParameterTypes(Executable executable) { public CodeBlock generateExecutableParameterTypes(Executable executable) {
Class<?>[] parameterTypes = Arrays.stream(executable.getParameters()) Class<?>[] parameterTypes = Arrays.stream(executable.getParameters())
.map(Parameter::getType).toArray(Class<?>[]::new); .map(Parameter::getType).toArray(Class<?>[]::new);
return CodeBlock.of(Arrays.stream(parameterTypes).map(d -> "$T.class") return CodeBlock.of(Arrays.stream(parameterTypes).map(d -> "$T.class")
.collect(Collectors.joining(", ")), (Object[]) parameterTypes); .collect(Collectors.joining(", ")), (Object[]) parameterTypes);
} }
private void writeParameterValue(Builder code, @Nullable Object value, Supplier<ResolvableType> parameterTypeSupplier) { private void generateParameterValue(Builder code, @Nullable Object value, Supplier<ResolvableType> parameterTypeSupplier) {
if (value == null) { if (value == null) {
code.add("null"); code.add("null");
return; return;
@ -115,7 +115,7 @@ public final class BeanParameterGenerator {
ResolvableType parameterType = parameterTypeSupplier.get(); ResolvableType parameterType = parameterTypeSupplier.get();
if (parameterType.isArray()) { if (parameterType.isArray()) {
code.add("new $T { ", parameterType.toClass()); code.add("new $T { ", parameterType.toClass());
code.add(writeAll(Arrays.asList(ObjectUtils.toObjectArray(value)), code.add(generateAll(Arrays.asList(ObjectUtils.toObjectArray(value)),
item -> parameterType.getComponentType())); item -> parameterType.getComponentType()));
code.add(" }"); code.add(" }");
} }
@ -127,7 +127,7 @@ public final class BeanParameterGenerator {
Class<?> listType = (value instanceof ManagedList ? ManagedList.class : List.class); Class<?> listType = (value instanceof ManagedList ? ManagedList.class : List.class);
code.add("$T.of(", listType); code.add("$T.of(", listType);
ResolvableType collectionType = parameterType.as(List.class).getGenerics()[0]; ResolvableType collectionType = parameterType.as(List.class).getGenerics()[0];
code.add(writeAll(list, item -> collectionType)); code.add(generateAll(list, item -> collectionType));
code.add(")"); code.add(")");
} }
} }
@ -139,7 +139,7 @@ public final class BeanParameterGenerator {
Class<?> setType = (value instanceof ManagedSet ? ManagedSet.class : Set.class); Class<?> setType = (value instanceof ManagedSet ? ManagedSet.class : Set.class);
code.add("$T.of(", setType); code.add("$T.of(", setType);
ResolvableType collectionType = parameterType.as(Set.class).getGenerics()[0]; ResolvableType collectionType = parameterType.as(Set.class).getGenerics()[0];
code.add(writeAll(set, item -> collectionType)); code.add(generateAll(set, item -> collectionType));
code.add(")"); code.add(")");
} }
} }
@ -151,7 +151,7 @@ public final class BeanParameterGenerator {
parameters.add(mapKey); parameters.add(mapKey);
parameters.add(mapValue); parameters.add(mapValue);
}); });
code.add(writeAll(parameters, ResolvableType::forInstance)); code.add(generateAll(parameters, ResolvableType::forInstance));
code.add(")"); code.add(")");
} }
} }
@ -175,7 +175,7 @@ public final class BeanParameterGenerator {
code.add(this.typeGenerator.generateTypeFor((ResolvableType) value)); code.add(this.typeGenerator.generateTypeFor((ResolvableType) value));
} }
else if (value instanceof BeanDefinition) { else if (value instanceof BeanDefinition) {
this.innerBeanDefinitionWriter.accept((BeanDefinition) value, code); this.innerBeanDefinitionGenerator.accept((BeanDefinition) value, code);
} }
else if (value instanceof BeanReference) { else if (value instanceof BeanReference) {
code.add("new $T($S)", RuntimeBeanReference.class, ((BeanReference) value).getBeanName()); code.add("new $T($S)", RuntimeBeanReference.class, ((BeanReference) value).getBeanName());
@ -185,10 +185,10 @@ public final class BeanParameterGenerator {
} }
} }
private <T> CodeBlock writeAll(Iterable<T> items, Function<T, ResolvableType> elementType) { private <T> CodeBlock generateAll(Iterable<T> items, Function<T, ResolvableType> elementType) {
MultiCodeBlock multi = new MultiCodeBlock(); MultiCodeBlock multi = new MultiCodeBlock();
items.forEach(item -> multi.add(code -> items.forEach(item -> multi.add(code ->
writeParameterValue(code, item, () -> elementType.apply(item)))); generateParameterValue(code, item, () -> elementType.apply(item))));
return multi.join(", "); return multi.join(", ");
} }

View File

@ -33,7 +33,7 @@ import org.springframework.javapoet.CodeBlock;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
/** /**
* Write the necessary statements to instantiate a bean. * Generate the necessary statements to instantiate a bean.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @see BeanInstantiationContribution * @see BeanInstantiationContribution
@ -64,18 +64,18 @@ class DefaultBeanInstantiationGenerator {
* @return a code contribution that provides an initialized bean instance * @return a code contribution that provides an initialized bean instance
*/ */
public CodeContribution generateBeanInstantiation(RuntimeHints runtimeHints) { public CodeContribution generateBeanInstantiation(RuntimeHints runtimeHints) {
DefaultCodeContribution contribution = new DefaultCodeContribution(runtimeHints); DefaultCodeContribution codeContribution = new DefaultCodeContribution(runtimeHints);
contribution.protectedAccess().analyze(this.instanceCreator, this.beanInstanceOptions); codeContribution.protectedAccess().analyze(this.instanceCreator, this.beanInstanceOptions);
if (this.instanceCreator instanceof Constructor<?> constructor) { if (this.instanceCreator instanceof Constructor<?> constructor) {
writeBeanInstantiation(contribution, constructor); generateBeanInstantiation(codeContribution, constructor);
} }
else if (this.instanceCreator instanceof Method method) { else if (this.instanceCreator instanceof Method method) {
writeBeanInstantiation(contribution, method); generateBeanInstantiation(codeContribution, method);
} }
return contribution; return codeContribution;
} }
private void writeBeanInstantiation(CodeContribution contribution, Constructor<?> constructor) { private void generateBeanInstantiation(CodeContribution codeContribution, Constructor<?> constructor) {
Class<?> declaringType = ClassUtils.getUserClass(constructor.getDeclaringClass()); Class<?> declaringType = ClassUtils.getUserClass(constructor.getDeclaringClass());
boolean innerClass = isInnerClass(declaringType); boolean innerClass = isInnerClass(declaringType);
boolean multiStatements = !this.contributions.isEmpty(); boolean multiStatements = !this.contributions.isEmpty();
@ -96,24 +96,24 @@ class DefaultBeanInstantiationGenerator {
code.add("$T::new", declaringType); code.add("$T::new", declaringType);
} }
} }
contribution.statements().addStatement(code.build()); codeContribution.statements().addStatement(code.build());
return; return;
} }
contribution.runtimeHints().reflection().registerConstructor(constructor, codeContribution.runtimeHints().reflection().registerConstructor(constructor,
hint -> hint.withMode(ExecutableMode.INTROSPECT)); hint -> hint.withMode(ExecutableMode.INTROSPECT));
code.add("(instanceContext) ->"); code.add("(instanceContext) ->");
branch(multiStatements, () -> code.beginControlFlow(""), () -> code.add(" ")); branch(multiStatements, () -> code.beginControlFlow(""), () -> code.add(" "));
if (multiStatements) { if (multiStatements) {
code.add("$T bean = ", declaringType); code.add("$T bean = ", declaringType);
} }
code.add(this.injectionGenerator.writeInstantiation(constructor)); code.add(this.injectionGenerator.generateInstantiation(constructor));
contribution.statements().addStatement(code.build()); codeContribution.statements().addStatement(code.build());
if (multiStatements) { if (multiStatements) {
for (BeanInstantiationContribution contributor : this.contributions) { for (BeanInstantiationContribution contribution : this.contributions) {
contributor.applyTo(contribution); contribution.applyTo(codeContribution);
} }
contribution.statements().addStatement("return bean") codeContribution.statements().addStatement("return bean")
.add(codeBlock -> codeBlock.unindent().add("}")); .add(codeBlock -> codeBlock.unindent().add("}"));
} }
} }
@ -122,9 +122,9 @@ class DefaultBeanInstantiationGenerator {
return type.isMemberClass() && !Modifier.isStatic(type.getModifiers()); return type.isMemberClass() && !Modifier.isStatic(type.getModifiers());
} }
private void writeBeanInstantiation(CodeContribution contribution, Method method) { private void generateBeanInstantiation(CodeContribution codeContribution, Method method) {
// Factory method can be introspected // Factory method can be introspected
contribution.runtimeHints().reflection().registerMethod(method, codeContribution.runtimeHints().reflection().registerMethod(method,
hint -> hint.withMode(ExecutableMode.INTROSPECT)); hint -> hint.withMode(ExecutableMode.INTROSPECT));
List<Class<?>> parameterTypes = new ArrayList<>(Arrays.asList(method.getParameterTypes())); List<Class<?>> parameterTypes = new ArrayList<>(Arrays.asList(method.getParameterTypes()));
boolean multiStatements = !this.contributions.isEmpty(); boolean multiStatements = !this.contributions.isEmpty();
@ -137,7 +137,7 @@ class DefaultBeanInstantiationGenerator {
() -> code.add("$T", declaringType), () -> code.add("$T", declaringType),
() -> code.add("beanFactory.getBean($T.class)", declaringType)); () -> code.add("beanFactory.getBean($T.class)", declaringType));
code.add(".$L()", method.getName()); code.add(".$L()", method.getName());
contribution.statements().addStatement(code.build()); codeContribution.statements().addStatement(code.build());
return; return;
} }
code.add("(instanceContext) ->"); code.add("(instanceContext) ->");
@ -145,13 +145,13 @@ class DefaultBeanInstantiationGenerator {
if (multiStatements) { if (multiStatements) {
code.add("$T bean = ", method.getReturnType()); code.add("$T bean = ", method.getReturnType());
} }
code.add(this.injectionGenerator.writeInstantiation(method)); code.add(this.injectionGenerator.generateInstantiation(method));
contribution.statements().addStatement(code.build()); codeContribution.statements().addStatement(code.build());
if (multiStatements) { if (multiStatements) {
for (BeanInstantiationContribution contributor : this.contributions) { for (BeanInstantiationContribution contribution : this.contributions) {
contributor.applyTo(contribution); contribution.applyTo(codeContribution);
} }
contribution.statements().addStatement("return bean") codeContribution.statements().addStatement("return bean")
.add(codeBlock -> codeBlock.unindent().add("}")); .add(codeBlock -> codeBlock.unindent().add("}"));
} }
} }

View File

@ -37,8 +37,8 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
/** /**
* Generate the necessary code to {@link #writeInstantiation(Executable) * Generate the necessary code to {@link #generateInstantiation(Executable)
* create a bean instance} or {@link #writeInjection(Member, boolean) * create a bean instance} or {@link #generateInjection(Member, boolean)
* inject dependencies}. * inject dependencies}.
* <p/> * <p/>
* The generator assumes a number of variables to be accessible: * The generator assumes a number of variables to be accessible:
@ -63,37 +63,37 @@ public class InjectionGenerator {
/** /**
* Write the necessary code to instantiate an object using the specified * Generate the necessary code to instantiate an object using the specified
* {@link Executable}. The code is suitable to be assigned to a variable * {@link Executable}. The code is suitable to be assigned to a variable
* or used as a {@literal return} statement. * or used as a {@literal return} statement.
* @param creator the executable to invoke to create an instance of the * @param creator the executable to invoke to create an instance of the
* requested object * requested object
* @return the code to instantiate an object using the specified executable * @return the code to instantiate an object using the specified executable
*/ */
public CodeBlock writeInstantiation(Executable creator) { public CodeBlock generateInstantiation(Executable creator) {
if (creator instanceof Constructor<?> constructor) { if (creator instanceof Constructor<?> constructor) {
return write(constructor); return generateConstructorInstantiation(constructor);
} }
if (creator instanceof Method method) { if (creator instanceof Method method) {
return writeMethodInstantiation(method); return generateMethodInstantiation(method);
} }
throw new IllegalArgumentException("Could not handle creator " + creator); throw new IllegalArgumentException("Could not handle creator " + creator);
} }
/** /**
* Write the code to inject a value resolved by {@link BeanInstanceContext} * Generate the code to inject a value resolved by {@link BeanInstanceContext}
* in the specified {@link Member}. * in the specified {@link Member}.
* @param member the field or method to inject * @param member the field or method to inject
* @param required whether the value is required * @param required whether the value is required
* @return a statement that injects a value to the specified member * @return a statement that injects a value to the specified member
* @see #getProtectedAccessInjectionOptions(Member) * @see #getProtectedAccessInjectionOptions(Member)
*/ */
public CodeBlock writeInjection(Member member, boolean required) { public CodeBlock generateInjection(Member member, boolean required) {
if (member instanceof Method method) { if (member instanceof Method method) {
return writeMethodInjection(method, required); return generateMethodInjection(method, required);
} }
if (member instanceof Field field) { if (member instanceof Field field) {
return writeFieldInjection(field, required); return generateFieldInjection(field, required);
} }
throw new IllegalArgumentException("Could not handle member " + member); throw new IllegalArgumentException("Could not handle member " + member);
} }
@ -115,7 +115,7 @@ public class InjectionGenerator {
throw new IllegalArgumentException("Could not handle member " + member); throw new IllegalArgumentException("Could not handle member " + member);
} }
private CodeBlock write(Constructor<?> creator) { private CodeBlock generateConstructorInstantiation(Constructor<?> creator) {
Builder code = CodeBlock.builder(); Builder code = CodeBlock.builder();
Class<?> declaringType = ClassUtils.getUserClass(creator.getDeclaringClass()); Class<?> declaringType = ClassUtils.getUserClass(creator.getDeclaringClass());
boolean innerClass = isInnerClass(declaringType); boolean innerClass = isInnerClass(declaringType);
@ -162,7 +162,7 @@ public class InjectionGenerator {
return type.isMemberClass() && !Modifier.isStatic(type.getModifiers()); return type.isMemberClass() && !Modifier.isStatic(type.getModifiers());
} }
private CodeBlock writeMethodInstantiation(Method injectionPoint) { private CodeBlock generateMethodInstantiation(Method injectionPoint) {
if (injectionPoint.getParameterCount() == 0) { if (injectionPoint.getParameterCount() == 0) {
Builder code = CodeBlock.builder(); Builder code = CodeBlock.builder();
Class<?> declaringType = injectionPoint.getDeclaringClass(); Class<?> declaringType = injectionPoint.getDeclaringClass();
@ -175,10 +175,10 @@ public class InjectionGenerator {
code.add(".$L()", injectionPoint.getName()); code.add(".$L()", injectionPoint.getName());
return code.build(); return code.build();
} }
return write(injectionPoint, code -> code.add(".create(beanFactory, (attributes) ->"), true); return generateMethodInvocation(injectionPoint, code -> code.add(".create(beanFactory, (attributes) ->"), true);
} }
private CodeBlock writeMethodInjection(Method injectionPoint, boolean required) { private CodeBlock generateMethodInjection(Method injectionPoint, boolean required) {
Consumer<Builder> attributesResolver = code -> { Consumer<Builder> attributesResolver = code -> {
if (required) { if (required) {
code.add(".invoke(beanFactory, (attributes) ->"); code.add(".invoke(beanFactory, (attributes) ->");
@ -187,15 +187,15 @@ public class InjectionGenerator {
code.add(".resolve(beanFactory, false).ifResolved((attributes) ->"); code.add(".resolve(beanFactory, false).ifResolved((attributes) ->");
} }
}; };
return write(injectionPoint, attributesResolver, false); return generateMethodInvocation(injectionPoint, attributesResolver, false);
} }
private CodeBlock write(Method injectionPoint, Consumer<Builder> attributesResolver, boolean instantiation) { private CodeBlock generateMethodInvocation(Method injectionPoint, Consumer<Builder> attributesResolver, boolean instantiation) {
Builder code = CodeBlock.builder(); Builder code = CodeBlock.builder();
code.add("instanceContext"); code.add("instanceContext");
if (!instantiation) { if (!instantiation) {
code.add(".method($S, ", injectionPoint.getName()); code.add(".method($S, ", injectionPoint.getName());
code.add(this.parameterGenerator.writeExecutableParameterTypes(injectionPoint)); code.add(this.parameterGenerator.generateExecutableParameterTypes(injectionPoint));
code.add(")\n").indent().indent(); code.add(")\n").indent().indent();
} }
attributesResolver.accept(code); attributesResolver.accept(code);
@ -222,7 +222,7 @@ public class InjectionGenerator {
return code.build(); return code.build();
} }
CodeBlock writeFieldInjection(Field injectionPoint, boolean required) { CodeBlock generateFieldInjection(Field injectionPoint, boolean required) {
Builder code = CodeBlock.builder(); Builder code = CodeBlock.builder();
code.add("instanceContext.field($S, $T.class", injectionPoint.getName(), injectionPoint.getType()); code.add("instanceContext.field($S, $T.class", injectionPoint.getName(), injectionPoint.getType());
code.add(")\n").indent().indent(); code.add(")\n").indent().indent();

View File

@ -41,6 +41,7 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
import org.springframework.javapoet.support.CodeSnippet; import org.springframework.javapoet.support.CodeSnippet;
import org.springframework.lang.Nullable;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -59,21 +60,21 @@ class BeanParameterGeneratorTests {
private final BeanParameterGenerator generator = new BeanParameterGenerator(); private final BeanParameterGenerator generator = new BeanParameterGenerator();
@Test @Test
void writeCharArray() { void generateCharArray() {
char[] value = new char[] { 'v', 'a', 'l', 'u', 'e' }; char[] value = new char[] { 'v', 'a', 'l', 'u', 'e' };
assertThat(write(value, ResolvableType.forArrayComponent(ResolvableType.forClass(char.class)))) assertThat(generate(value, ResolvableType.forArrayComponent(ResolvableType.forClass(char.class))))
.isEqualTo("new char[] { 'v', 'a', 'l', 'u', 'e' }"); .isEqualTo("new char[] { 'v', 'a', 'l', 'u', 'e' }");
} }
@Test @Test
void writeStringArray() { void generateStringArray() {
String[] value = new String[] { "a", "test" }; String[] value = new String[] { "a", "test" };
assertThat(write(value, ResolvableType.forArrayComponent(ResolvableType.forClass(String.class)))) assertThat(generate(value, ResolvableType.forArrayComponent(ResolvableType.forClass(String.class))))
.isEqualTo("new String[] { \"a\", \"test\" }"); .isEqualTo("new String[] { \"a\", \"test\" }");
} }
@Test @Test
void writeStringList() { void generateStringList() {
List<String> value = List.of("a", "test"); List<String> value = List.of("a", "test");
CodeSnippet code = codeSnippet(value, ResolvableType.forClassWithGenerics(List.class, String.class)); CodeSnippet code = codeSnippet(value, ResolvableType.forClassWithGenerics(List.class, String.class));
assertThat(code.getSnippet()).isEqualTo( assertThat(code.getSnippet()).isEqualTo(
@ -82,7 +83,7 @@ class BeanParameterGeneratorTests {
} }
@Test @Test
void writeStringManagedList() { void generateStringManagedList() {
ManagedList<String> value = ManagedList.of("a", "test"); ManagedList<String> value = ManagedList.of("a", "test");
CodeSnippet code = codeSnippet(value, ResolvableType.forClassWithGenerics(List.class, String.class)); CodeSnippet code = codeSnippet(value, ResolvableType.forClassWithGenerics(List.class, String.class));
assertThat(code.getSnippet()).isEqualTo( assertThat(code.getSnippet()).isEqualTo(
@ -91,7 +92,7 @@ class BeanParameterGeneratorTests {
} }
@Test @Test
void writeEmptyList() { void generateEmptyList() {
List<String> value = List.of(); List<String> value = List.of();
CodeSnippet code = codeSnippet(value, ResolvableType.forClassWithGenerics(List.class, String.class)); CodeSnippet code = codeSnippet(value, ResolvableType.forClassWithGenerics(List.class, String.class));
assertThat(code.getSnippet()).isEqualTo("Collections.emptyList()"); assertThat(code.getSnippet()).isEqualTo("Collections.emptyList()");
@ -99,7 +100,7 @@ class BeanParameterGeneratorTests {
} }
@Test @Test
void writeStringSet() { void generateStringSet() {
Set<String> value = Set.of("a", "test"); Set<String> value = Set.of("a", "test");
CodeSnippet code = codeSnippet(value, ResolvableType.forClassWithGenerics(Set.class, String.class)); CodeSnippet code = codeSnippet(value, ResolvableType.forClassWithGenerics(Set.class, String.class));
assertThat(code.getSnippet()).startsWith("Set.of(").contains("a").contains("test"); assertThat(code.getSnippet()).startsWith("Set.of(").contains("a").contains("test");
@ -107,7 +108,7 @@ class BeanParameterGeneratorTests {
} }
@Test @Test
void writeStringManagedSet() { void generateStringManagedSet() {
Set<String> value = ManagedSet.of("a", "test"); Set<String> value = ManagedSet.of("a", "test");
CodeSnippet code = codeSnippet(value, ResolvableType.forClassWithGenerics(Set.class, String.class)); CodeSnippet code = codeSnippet(value, ResolvableType.forClassWithGenerics(Set.class, String.class));
assertThat(code.getSnippet()).isEqualTo( assertThat(code.getSnippet()).isEqualTo(
@ -116,7 +117,7 @@ class BeanParameterGeneratorTests {
} }
@Test @Test
void writeEmptySet() { void generateEmptySet() {
Set<String> value = Set.of(); Set<String> value = Set.of();
CodeSnippet code = codeSnippet(value, ResolvableType.forClassWithGenerics(Set.class, String.class)); CodeSnippet code = codeSnippet(value, ResolvableType.forClassWithGenerics(Set.class, String.class));
assertThat(code.getSnippet()).isEqualTo("Collections.emptySet()"); assertThat(code.getSnippet()).isEqualTo("Collections.emptySet()");
@ -124,39 +125,39 @@ class BeanParameterGeneratorTests {
} }
@Test @Test
void writeMap() { void generateMap() {
Map<String, Object> value = new LinkedHashMap<>(); Map<String, Object> value = new LinkedHashMap<>();
value.put("name", "Hello"); value.put("name", "Hello");
value.put("counter", 42); value.put("counter", 42);
assertThat(write(value)).isEqualTo("Map.of(\"name\", \"Hello\", \"counter\", 42)"); assertThat(generate(value)).isEqualTo("Map.of(\"name\", \"Hello\", \"counter\", 42)");
} }
@Test @Test
void writeMapWithEnum() { void generateMapWithEnum() {
Map<String, Object> value = new HashMap<>(); Map<String, Object> value = new HashMap<>();
value.put("unit", ChronoUnit.DAYS); value.put("unit", ChronoUnit.DAYS);
assertThat(write(value)).isEqualTo("Map.of(\"unit\", ChronoUnit.DAYS)"); assertThat(generate(value)).isEqualTo("Map.of(\"unit\", ChronoUnit.DAYS)");
} }
@Test @Test
void writeEmptyMap() { void generateEmptyMap() {
assertThat(write(Map.of())).isEqualTo("Map.of()"); assertThat(generate(Map.of())).isEqualTo("Map.of()");
} }
@Test @Test
void writeString() { void generateString() {
assertThat(write("test", ResolvableType.forClass(String.class))).isEqualTo("\"test\""); assertThat(generate("test", ResolvableType.forClass(String.class))).isEqualTo("\"test\"");
} }
@Test @Test
void writeCharEscapeBackslash() { void generateCharEscapeBackslash() {
assertThat(write('\\', ResolvableType.forType(char.class))).isEqualTo("'\\\\'"); assertThat(generate('\\', ResolvableType.forType(char.class))).isEqualTo("'\\\\'");
} }
@ParameterizedTest @ParameterizedTest
@MethodSource("primitiveValues") @MethodSource("primitiveValues")
void writePrimitiveValue(Object value, String parameter) { void generatePrimitiveValue(Object value, String parameter) {
assertThat(write(value, ResolvableType.forClass(value.getClass()))).isEqualTo(parameter); assertThat(generate(value, ResolvableType.forClass(value.getClass()))).isEqualTo(parameter);
} }
private static Stream<Arguments> primitiveValues() { private static Stream<Arguments> primitiveValues() {
@ -166,87 +167,88 @@ class BeanParameterGeneratorTests {
} }
@Test @Test
void writeEnum() { void generateEnum() {
assertThat(write(ChronoUnit.DAYS, ResolvableType.forClass(ChronoUnit.class))) assertThat(generate(ChronoUnit.DAYS, ResolvableType.forClass(ChronoUnit.class)))
.isEqualTo("ChronoUnit.DAYS"); .isEqualTo("ChronoUnit.DAYS");
} }
@Test @Test
void writeClass() { void generateClass() {
assertThat(write(Integer.class, ResolvableType.forClass(Class.class))) assertThat(generate(Integer.class, ResolvableType.forClass(Class.class)))
.isEqualTo("Integer.class"); .isEqualTo("Integer.class");
} }
@Test @Test
void writeResolvableType() { void generateResolvableType() {
ResolvableType type = ResolvableType.forClassWithGenerics(Consumer.class, Integer.class); ResolvableType type = ResolvableType.forClassWithGenerics(Consumer.class, Integer.class);
assertThat(write(type, type)) assertThat(generate(type, type))
.isEqualTo("ResolvableType.forClassWithGenerics(Consumer.class, Integer.class)"); .isEqualTo("ResolvableType.forClassWithGenerics(Consumer.class, Integer.class)");
} }
@Test @Test
void writeExecutableParameterTypesWithConstructor() { void generateExecutableParameterTypesWithConstructor() {
Constructor<?> constructor = TestSample.class.getDeclaredConstructors()[0]; Constructor<?> constructor = TestSample.class.getDeclaredConstructors()[0];
assertThat(CodeSnippet.process(this.generator.writeExecutableParameterTypes(constructor))) assertThat(CodeSnippet.process(this.generator.generateExecutableParameterTypes(constructor)))
.isEqualTo("String.class, ResourceLoader.class"); .isEqualTo("String.class, ResourceLoader.class");
} }
@Test @Test
void writeExecutableParameterTypesWithNoArgConstructor() { void generateExecutableParameterTypesWithNoArgConstructor() {
Constructor<?> constructor = BeanParameterGeneratorTests.class.getDeclaredConstructors()[0]; Constructor<?> constructor = BeanParameterGeneratorTests.class.getDeclaredConstructors()[0];
assertThat(CodeSnippet.process(this.generator.writeExecutableParameterTypes(constructor))) assertThat(CodeSnippet.process(this.generator.generateExecutableParameterTypes(constructor)))
.isEmpty(); .isEmpty();
} }
@Test @Test
void writeExecutableParameterTypesWithMethod() { void generateExecutableParameterTypesWithMethod() {
Method method = ReflectionUtils.findMethod(TestSample.class, "createBean", String.class, Integer.class); Method method = ReflectionUtils.findMethod(TestSample.class, "createBean", String.class, Integer.class);
assertThat(CodeSnippet.process(this.generator.writeExecutableParameterTypes(method))) assertThat(CodeSnippet.process(this.generator.generateExecutableParameterTypes(method)))
.isEqualTo("String.class, Integer.class"); .isEqualTo("String.class, Integer.class");
} }
@Test @Test
void writeNull() { void generateNull() {
assertThat(write(null)).isEqualTo("null"); assertThat(generate(null)).isEqualTo("null");
} }
@Test @Test
void writeBeanReference() { void generateBeanReference() {
BeanReference beanReference = mock(BeanReference.class); BeanReference beanReference = mock(BeanReference.class);
given(beanReference.getBeanName()).willReturn("testBean"); given(beanReference.getBeanName()).willReturn("testBean");
assertThat(write(beanReference)).isEqualTo("new RuntimeBeanReference(\"testBean\")"); assertThat(generate(beanReference)).isEqualTo("new RuntimeBeanReference(\"testBean\")");
} }
@Test @Test
void writeBeanDefinitionCallsConsumer() { void generateBeanDefinitionCallsConsumer() {
BeanParameterGenerator customGenerator = new BeanParameterGenerator( BeanParameterGenerator customGenerator = new BeanParameterGenerator(
((beanDefinition, builder) -> builder.add("test"))); ((beanDefinition, builder) -> builder.add("test")));
assertThat(CodeSnippet.process(customGenerator.writeParameterValue(new RootBeanDefinition()))).isEqualTo("test"); assertThat(CodeSnippet.process(customGenerator.generateParameterValue(
new RootBeanDefinition()))).isEqualTo("test");
} }
@Test @Test
void writeBeanDefinitionWithoutConsumerFails() { void generateBeanDefinitionWithoutConsumerFails() {
BeanParameterGenerator customGenerator = new BeanParameterGenerator(); BeanParameterGenerator customGenerator = new BeanParameterGenerator();
assertThatIllegalStateException().isThrownBy(() -> customGenerator assertThatIllegalStateException().isThrownBy(() -> customGenerator
.writeParameterValue(new RootBeanDefinition())); .generateParameterValue(new RootBeanDefinition()));
} }
@Test @Test
void writeUnsupportedParameter() { void generateUnsupportedParameter() {
assertThatIllegalArgumentException().isThrownBy(() -> write(new StringWriter())) assertThatIllegalArgumentException().isThrownBy(() -> generate(new StringWriter()))
.withMessageContaining(StringWriter.class.getName()); .withMessageContaining(StringWriter.class.getName());
} }
private String write(Object value) { private String generate(@Nullable Object value) {
return CodeSnippet.process(this.generator.writeParameterValue(value)); return CodeSnippet.process(this.generator.generateParameterValue(value));
} }
private String write(Object value, ResolvableType resolvableType) { private String generate(Object value, ResolvableType resolvableType) {
return codeSnippet(value, resolvableType).getSnippet(); return codeSnippet(value, resolvableType).getSnippet();
} }
private CodeSnippet codeSnippet(Object value, ResolvableType resolvableType) { private CodeSnippet codeSnippet(Object value, ResolvableType resolvableType) {
return CodeSnippet.of(this.generator.writeParameterValue(value, () -> resolvableType)); return CodeSnippet.of(this.generator.generateParameterValue(value, () -> resolvableType));
} }

View File

@ -45,119 +45,119 @@ class InjectionGeneratorTests {
private final ProtectedAccess protectedAccess = new ProtectedAccess(); private final ProtectedAccess protectedAccess = new ProtectedAccess();
@Test @Test
void writeInstantiationForConstructorWithNoArgUseShortcut() { void generateInstantiationForConstructorWithNoArgUseShortcut() {
Constructor<?> constructor = SimpleBean.class.getDeclaredConstructors()[0]; Constructor<?> constructor = SimpleBean.class.getDeclaredConstructors()[0];
assertThat(writeInstantiation(constructor).lines()) assertThat(generateInstantiation(constructor).lines())
.containsExactly("new InjectionGeneratorTests.SimpleBean()"); .containsExactly("new InjectionGeneratorTests.SimpleBean()");
} }
@Test @Test
void writeInstantiationForConstructorWithNonGenericParameter() { void generateInstantiationForConstructorWithNonGenericParameter() {
Constructor<?> constructor = SimpleConstructorBean.class.getDeclaredConstructors()[0]; Constructor<?> constructor = SimpleConstructorBean.class.getDeclaredConstructors()[0];
assertThat(writeInstantiation(constructor).lines()).containsExactly( assertThat(generateInstantiation(constructor).lines()).containsExactly(
"instanceContext.create(beanFactory, (attributes) -> new InjectionGeneratorTests.SimpleConstructorBean(attributes.get(0), attributes.get(1)))"); "instanceContext.create(beanFactory, (attributes) -> new InjectionGeneratorTests.SimpleConstructorBean(attributes.get(0), attributes.get(1)))");
} }
@Test @Test
void writeInstantiationForConstructorWithGenericParameter() { void generateInstantiationForConstructorWithGenericParameter() {
Constructor<?> constructor = GenericConstructorBean.class.getDeclaredConstructors()[0]; Constructor<?> constructor = GenericConstructorBean.class.getDeclaredConstructors()[0];
assertThat(writeInstantiation(constructor).lines()).containsExactly( assertThat(generateInstantiation(constructor).lines()).containsExactly(
"instanceContext.create(beanFactory, (attributes) -> new InjectionGeneratorTests.GenericConstructorBean(attributes.get(0)))"); "instanceContext.create(beanFactory, (attributes) -> new InjectionGeneratorTests.GenericConstructorBean(attributes.get(0)))");
} }
@Test @Test
void writeInstantiationForAmbiguousConstructor() throws Exception { void generateInstantiationForAmbiguousConstructor() throws Exception {
Constructor<?> constructor = AmbiguousConstructorBean.class.getDeclaredConstructor(String.class, Number.class); Constructor<?> constructor = AmbiguousConstructorBean.class.getDeclaredConstructor(String.class, Number.class);
assertThat(writeInstantiation(constructor).lines()).containsExactly( assertThat(generateInstantiation(constructor).lines()).containsExactly(
"instanceContext.create(beanFactory, (attributes) -> new InjectionGeneratorTests.AmbiguousConstructorBean(attributes.get(0, String.class), attributes.get(1, Number.class)))"); "instanceContext.create(beanFactory, (attributes) -> new InjectionGeneratorTests.AmbiguousConstructorBean(attributes.get(0, String.class), attributes.get(1, Number.class)))");
} }
@Test @Test
void writeInstantiationForConstructorInInnerClass() { void generateInstantiationForConstructorInInnerClass() {
Constructor<?> constructor = InnerClass.class.getDeclaredConstructors()[0]; Constructor<?> constructor = InnerClass.class.getDeclaredConstructors()[0];
assertThat(writeInstantiation(constructor).lines()).containsExactly( assertThat(generateInstantiation(constructor).lines()).containsExactly(
"beanFactory.getBean(InjectionGeneratorTests.SimpleConstructorBean.class).new InnerClass()"); "beanFactory.getBean(InjectionGeneratorTests.SimpleConstructorBean.class).new InnerClass()");
} }
@Test @Test
void writeInstantiationForMethodWithNoArgUseShortcut() { void generateInstantiationForMethodWithNoArgUseShortcut() {
assertThat(writeInstantiation(method(SimpleBean.class, "name")).lines()).containsExactly( assertThat(generateInstantiation(method(SimpleBean.class, "name")).lines()).containsExactly(
"beanFactory.getBean(InjectionGeneratorTests.SimpleBean.class).name()"); "beanFactory.getBean(InjectionGeneratorTests.SimpleBean.class).name()");
} }
@Test @Test
void writeInstantiationForStaticMethodWithNoArgUseShortcut() { void generateInstantiationForStaticMethodWithNoArgUseShortcut() {
assertThat(writeInstantiation(method(SimpleBean.class, "number")).lines()).containsExactly( assertThat(generateInstantiation(method(SimpleBean.class, "number")).lines()).containsExactly(
"InjectionGeneratorTests.SimpleBean.number()"); "InjectionGeneratorTests.SimpleBean.number()");
} }
@Test @Test
void writeInstantiationForMethodWithNonGenericParameter() { void generateInstantiationForMethodWithNonGenericParameter() {
assertThat(writeInstantiation(method(SampleBean.class, "source", Integer.class)).lines()).containsExactly( assertThat(generateInstantiation(method(SampleBean.class, "source", Integer.class)).lines()).containsExactly(
"instanceContext.create(beanFactory, (attributes) -> beanFactory.getBean(InjectionGeneratorTests.SampleBean.class).source(attributes.get(0)))"); "instanceContext.create(beanFactory, (attributes) -> beanFactory.getBean(InjectionGeneratorTests.SampleBean.class).source(attributes.get(0)))");
} }
@Test @Test
void writeInstantiationForStaticMethodWithNonGenericParameter() { void generateInstantiationForStaticMethodWithNonGenericParameter() {
assertThat(writeInstantiation(method(SampleBean.class, "staticSource", Integer.class)).lines()).containsExactly( assertThat(generateInstantiation(method(SampleBean.class, "staticSource", Integer.class)).lines()).containsExactly(
"instanceContext.create(beanFactory, (attributes) -> InjectionGeneratorTests.SampleBean.staticSource(attributes.get(0)))"); "instanceContext.create(beanFactory, (attributes) -> InjectionGeneratorTests.SampleBean.staticSource(attributes.get(0)))");
} }
@Test @Test
void writeInstantiationForMethodWithGenericParameters() { void generateInstantiationForMethodWithGenericParameters() {
assertThat(writeInstantiation(method(SampleBean.class, "source", ObjectProvider.class)).lines()).containsExactly( assertThat(generateInstantiation(method(SampleBean.class, "source", ObjectProvider.class)).lines()).containsExactly(
"instanceContext.create(beanFactory, (attributes) -> beanFactory.getBean(InjectionGeneratorTests.SampleBean.class).source(attributes.get(0)))"); "instanceContext.create(beanFactory, (attributes) -> beanFactory.getBean(InjectionGeneratorTests.SampleBean.class).source(attributes.get(0)))");
} }
@Test @Test
void writeInjectionForUnsupportedMember() { void generateInjectionForUnsupportedMember() {
assertThatIllegalArgumentException().isThrownBy(() -> writeInjection(mock(Member.class), false)); assertThatIllegalArgumentException().isThrownBy(() -> generateInjection(mock(Member.class), false));
} }
@Test @Test
void writeInjectionForNonRequiredMethodWithNonGenericParameters() { void generateInjectionForNonRequiredMethodWithNonGenericParameters() {
Method method = method(SampleBean.class, "sourceAndCounter", String.class, Integer.class); Method method = method(SampleBean.class, "sourceAndCounter", String.class, Integer.class);
assertThat(writeInjection(method, false)).isEqualTo(""" assertThat(generateInjection(method, false)).isEqualTo("""
instanceContext.method("sourceAndCounter", String.class, Integer.class) instanceContext.method("sourceAndCounter", String.class, Integer.class)
.resolve(beanFactory, false).ifResolved((attributes) -> bean.sourceAndCounter(attributes.get(0), attributes.get(1)))"""); .resolve(beanFactory, false).ifResolved((attributes) -> bean.sourceAndCounter(attributes.get(0), attributes.get(1)))""");
} }
@Test @Test
void writeInjectionForRequiredMethodWithGenericParameter() { void generateInjectionForRequiredMethodWithGenericParameter() {
Method method = method(SampleBean.class, "nameAndCounter", String.class, ObjectProvider.class); Method method = method(SampleBean.class, "nameAndCounter", String.class, ObjectProvider.class);
assertThat(writeInjection(method, true)).isEqualTo(""" assertThat(generateInjection(method, true)).isEqualTo("""
instanceContext.method("nameAndCounter", String.class, ObjectProvider.class) instanceContext.method("nameAndCounter", String.class, ObjectProvider.class)
.invoke(beanFactory, (attributes) -> bean.nameAndCounter(attributes.get(0), attributes.get(1)))"""); .invoke(beanFactory, (attributes) -> bean.nameAndCounter(attributes.get(0), attributes.get(1)))""");
} }
@Test @Test
void writeInjectionForNonRequiredMethodWithGenericParameter() { void generateInjectionForNonRequiredMethodWithGenericParameter() {
Method method = method(SampleBean.class, "nameAndCounter", String.class, ObjectProvider.class); Method method = method(SampleBean.class, "nameAndCounter", String.class, ObjectProvider.class);
assertThat(writeInjection(method, false)).isEqualTo(""" assertThat(generateInjection(method, false)).isEqualTo("""
instanceContext.method("nameAndCounter", String.class, ObjectProvider.class) instanceContext.method("nameAndCounter", String.class, ObjectProvider.class)
.resolve(beanFactory, false).ifResolved((attributes) -> bean.nameAndCounter(attributes.get(0), attributes.get(1)))"""); .resolve(beanFactory, false).ifResolved((attributes) -> bean.nameAndCounter(attributes.get(0), attributes.get(1)))""");
} }
@Test @Test
void writeInjectionForRequiredField() { void generateInjectionForRequiredField() {
Field field = field(SampleBean.class, "counter"); Field field = field(SampleBean.class, "counter");
assertThat(writeInjection(field, true)).isEqualTo(""" assertThat(generateInjection(field, true)).isEqualTo("""
instanceContext.field("counter", Integer.class) instanceContext.field("counter", Integer.class)
.invoke(beanFactory, (attributes) -> bean.counter = attributes.get(0))"""); .invoke(beanFactory, (attributes) -> bean.counter = attributes.get(0))""");
} }
@Test @Test
void writeInjectionForNonRequiredField() { void generateInjectionForNonRequiredField() {
Field field = field(SampleBean.class, "counter"); Field field = field(SampleBean.class, "counter");
assertThat(writeInjection(field, false)).isEqualTo(""" assertThat(generateInjection(field, false)).isEqualTo("""
instanceContext.field("counter", Integer.class) instanceContext.field("counter", Integer.class)
.resolve(beanFactory, false).ifResolved((attributes) -> bean.counter = attributes.get(0))"""); .resolve(beanFactory, false).ifResolved((attributes) -> bean.counter = attributes.get(0))""");
} }
@Test @Test
void writeInjectionForRequiredPrivateField() { void generateInjectionForRequiredPrivateField() {
Field field = field(SampleBean.class, "source"); Field field = field(SampleBean.class, "source");
assertThat(writeInjection(field, true)).isEqualTo(""" assertThat(generateInjection(field, true)).isEqualTo("""
instanceContext.field("source", String.class) instanceContext.field("source", String.class)
.invoke(beanFactory, (attributes) -> { .invoke(beanFactory, (attributes) -> {
Field sourceField = ReflectionUtils.findField(InjectionGeneratorTests.SampleBean.class, "source", String.class); Field sourceField = ReflectionUtils.findField(InjectionGeneratorTests.SampleBean.class, "source", String.class);
@ -215,12 +215,12 @@ class InjectionGeneratorTests {
return field; return field;
} }
private String writeInstantiation(Executable creator) { private String generateInstantiation(Executable creator) {
return CodeSnippet.process(code -> code.add(new InjectionGenerator().writeInstantiation(creator))); return CodeSnippet.process(code -> code.add(new InjectionGenerator().generateInstantiation(creator)));
} }
private String writeInjection(Member member, boolean required) { private String generateInjection(Member member, boolean required) {
return CodeSnippet.process(code -> code.add(new InjectionGenerator().writeInjection(member, required))); return CodeSnippet.process(code -> code.add(new InjectionGenerator().generateInjection(member, required)));
} }
private void analyzeProtectedAccess(Member member) { private void analyzeProtectedAccess(Member member) {