Stop generating unnecessary reference to field type

This commit updates the generator to stop specifying a field type when
reflection is necessary, or when a reference to a field should be
retrieved as its name alone suffices.

This could trigger package protected issues if the field type is not
public.

See gh-28047
This commit is contained in:
Stephane Nicoll 2022-03-08 15:43:29 +01:00
parent e873715737
commit 9809752c3c
5 changed files with 22 additions and 24 deletions

View File

@ -224,7 +224,7 @@ public class InjectionGenerator {
CodeBlock generateFieldInjection(Field injectionPoint, boolean required) {
Builder code = CodeBlock.builder();
code.add("instanceContext.field($S, $T.class", injectionPoint.getName(), injectionPoint.getType());
code.add("instanceContext.field($S", injectionPoint.getName());
code.add(")\n").indent().indent();
if (required) {
code.add(".invoke(beanFactory, (attributes) ->");
@ -236,8 +236,8 @@ public class InjectionGenerator {
if (hasAssignment) {
code.beginControlFlow("");
String fieldName = String.format("%sField", injectionPoint.getName());
code.addStatement("$T $L = $T.findField($T.class, $S, $T.class)", Field.class, fieldName, ReflectionUtils.class,
injectionPoint.getDeclaringClass(), injectionPoint.getName(), injectionPoint.getType());
code.addStatement("$T $L = $T.findField($T.class, $S)", Field.class, fieldName, ReflectionUtils.class,
injectionPoint.getDeclaringClass(), injectionPoint.getName());
code.addStatement("$T.makeAccessible($L)", ReflectionUtils.class, fieldName);
code.addStatement("$T.setField($L, bean, attributes.get(0))", ReflectionUtils.class, fieldName);
code.unindent().add("}");

View File

@ -298,11 +298,10 @@ public final class BeanDefinitionRegistrar {
/**
* Create an {@link InjectedElementResolver} for the specified field.
* @param name the name of the field
* @param type the type of the field
* @return a resolved for the specified field
*/
public InjectedElementResolver field(String name, Class<?> type) {
return new InjectedFieldResolver(getField(name, type), this.beanName);
public InjectedElementResolver field(String name) {
return new InjectedFieldResolver(getField(name), this.beanName);
}
/**
@ -315,9 +314,9 @@ public final class BeanDefinitionRegistrar {
return new InjectedMethodResolver(getMethod(this.beanType, name, parameterTypes), this.beanType, this.beanName);
}
private Field getField(String fieldName, Class<?> fieldType) {
Field field = ReflectionUtils.findField(this.beanType, fieldName, fieldType);
Assert.notNull(field, () -> "No field '" + fieldName + "' with type " + fieldType.getName() + " found on " + this.beanType);
private Field getField(String fieldName) {
Field field = ReflectionUtils.findField(this.beanType, fieldName);
Assert.notNull(field, () -> "No field '" + fieldName + "' found on " + this.beanType.getName());
return field;
}

View File

@ -44,7 +44,7 @@ class AutowiredAnnotationBeanInstantiationContributionTests {
void contributeWithPackageProtectedFieldInjection() {
CodeContribution contribution = contribute(PackageProtectedFieldInjectionSample.class);
assertThat(CodeSnippet.process(contribution.statements().toCodeBlock())).isEqualTo("""
instanceContext.field("environment", Environment.class)
instanceContext.field("environment")
.invoke(beanFactory, (attributes) -> bean.environment = attributes.get(0))""");
assertThat(contribution.runtimeHints().reflection().typeHints()).singleElement().satisfies(typeHint -> {
assertThat(typeHint.getType()).isEqualTo(TypeReference.of(PackageProtectedFieldInjectionSample.class));
@ -62,9 +62,9 @@ class AutowiredAnnotationBeanInstantiationContributionTests {
void contributeWithPrivateFieldInjection() {
CodeContribution contribution = contribute(PrivateFieldInjectionSample.class);
assertThat(CodeSnippet.process(contribution.statements().toCodeBlock())).isEqualTo("""
instanceContext.field("environment", Environment.class)
instanceContext.field("environment")
.invoke(beanFactory, (attributes) -> {
Field environmentField = ReflectionUtils.findField(AutowiredAnnotationBeanInstantiationContributionTests.PrivateFieldInjectionSample.class, "environment", Environment.class);
Field environmentField = ReflectionUtils.findField(AutowiredAnnotationBeanInstantiationContributionTests.PrivateFieldInjectionSample.class, "environment");
ReflectionUtils.makeAccessible(environmentField);
ReflectionUtils.setField(environmentField, bean, attributes.get(0));
})""");
@ -99,9 +99,9 @@ class AutowiredAnnotationBeanInstantiationContributionTests {
void contributeWithInjectionPoints() {
CodeContribution contribution = contribute(ResourceInjectionBean.class);
assertThat(CodeSnippet.process(contribution.statements().toCodeBlock())).isEqualTo("""
instanceContext.field("testBean", TestBean.class)
instanceContext.field("testBean")
.resolve(beanFactory, false).ifResolved((attributes) -> {
Field testBeanField = ReflectionUtils.findField(AutowiredAnnotationBeanPostProcessorTests.ResourceInjectionBean.class, "testBean", TestBean.class);
Field testBeanField = ReflectionUtils.findField(AutowiredAnnotationBeanPostProcessorTests.ResourceInjectionBean.class, "testBean");
ReflectionUtils.makeAccessible(testBeanField);
ReflectionUtils.setField(testBeanField, bean, attributes.get(0));
});

View File

@ -142,7 +142,7 @@ class InjectionGeneratorTests {
void generateInjectionForRequiredField() {
Field field = field(SampleBean.class, "counter");
assertThat(generateInjection(field, true)).isEqualTo("""
instanceContext.field("counter", Integer.class)
instanceContext.field("counter")
.invoke(beanFactory, (attributes) -> bean.counter = attributes.get(0))""");
}
@ -150,7 +150,7 @@ class InjectionGeneratorTests {
void generateInjectionForNonRequiredField() {
Field field = field(SampleBean.class, "counter");
assertThat(generateInjection(field, false)).isEqualTo("""
instanceContext.field("counter", Integer.class)
instanceContext.field("counter")
.resolve(beanFactory, false).ifResolved((attributes) -> bean.counter = attributes.get(0))""");
}
@ -158,9 +158,9 @@ class InjectionGeneratorTests {
void generateInjectionForRequiredPrivateField() {
Field field = field(SampleBean.class, "source");
assertThat(generateInjection(field, true)).isEqualTo("""
instanceContext.field("source", String.class)
instanceContext.field("source")
.invoke(beanFactory, (attributes) -> {
Field sourceField = ReflectionUtils.findField(InjectionGeneratorTests.SampleBean.class, "source", String.class);
Field sourceField = ReflectionUtils.findField(InjectionGeneratorTests.SampleBean.class, "source");
ReflectionUtils.makeAccessible(sourceField);
ReflectionUtils.setField(sourceField, bean, attributes.get(0));
})""");

View File

@ -257,8 +257,8 @@ class BeanDefinitionRegistrarTests {
beanFactory.registerSingleton("environment", environment);
BeanDefinitionRegistrar.of("test", InjectionSample.class).instanceSupplier(instanceContext -> {
InjectionSample bean = new InjectionSample();
instanceContext.field("environment", Environment.class).invoke(beanFactory,
attributes -> bean.environment = (attributes.get(0)));
instanceContext.field("environment").invoke(beanFactory, attributes ->
bean.environment = (attributes.get(0)));
return bean;
}).register(beanFactory);
assertBeanFactory(beanFactory, () -> {
@ -271,11 +271,10 @@ class BeanDefinitionRegistrarTests {
void registerWithInvalidField() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinitionRegistrar.of("test", InjectionSample.class).instanceSupplier(instanceContext ->
instanceContext.field("doesNotExist", Object.class).resolve(beanFactory)).register(beanFactory);
instanceContext.field("doesNotExist").resolve(beanFactory)).register(beanFactory);
assertThatThrownBy(() -> beanFactory.getBean(InjectionSample.class)
).isInstanceOf(BeanCreationException.class)
.hasMessageContaining("No field '%s' with type %s found", "doesNotExist", Object.class.getName())
.hasMessageContaining(InjectionSample.class.getName());
).isInstanceOf(BeanCreationException.class).hasMessageContaining(
"No field 'doesNotExist' found on " + InjectionSample.class.getName());
}
@Test