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:
parent
e873715737
commit
9809752c3c
|
|
@ -224,7 +224,7 @@ public class InjectionGenerator {
|
||||||
|
|
||||||
CodeBlock generateFieldInjection(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", injectionPoint.getName());
|
||||||
code.add(")\n").indent().indent();
|
code.add(")\n").indent().indent();
|
||||||
if (required) {
|
if (required) {
|
||||||
code.add(".invoke(beanFactory, (attributes) ->");
|
code.add(".invoke(beanFactory, (attributes) ->");
|
||||||
|
|
@ -236,8 +236,8 @@ public class InjectionGenerator {
|
||||||
if (hasAssignment) {
|
if (hasAssignment) {
|
||||||
code.beginControlFlow("");
|
code.beginControlFlow("");
|
||||||
String fieldName = String.format("%sField", injectionPoint.getName());
|
String fieldName = String.format("%sField", injectionPoint.getName());
|
||||||
code.addStatement("$T $L = $T.findField($T.class, $S, $T.class)", Field.class, fieldName, ReflectionUtils.class,
|
code.addStatement("$T $L = $T.findField($T.class, $S)", Field.class, fieldName, ReflectionUtils.class,
|
||||||
injectionPoint.getDeclaringClass(), injectionPoint.getName(), injectionPoint.getType());
|
injectionPoint.getDeclaringClass(), injectionPoint.getName());
|
||||||
code.addStatement("$T.makeAccessible($L)", ReflectionUtils.class, fieldName);
|
code.addStatement("$T.makeAccessible($L)", ReflectionUtils.class, fieldName);
|
||||||
code.addStatement("$T.setField($L, bean, attributes.get(0))", ReflectionUtils.class, fieldName);
|
code.addStatement("$T.setField($L, bean, attributes.get(0))", ReflectionUtils.class, fieldName);
|
||||||
code.unindent().add("}");
|
code.unindent().add("}");
|
||||||
|
|
|
||||||
|
|
@ -298,11 +298,10 @@ public final class BeanDefinitionRegistrar {
|
||||||
/**
|
/**
|
||||||
* Create an {@link InjectedElementResolver} for the specified field.
|
* Create an {@link InjectedElementResolver} for the specified field.
|
||||||
* @param name the name of the field
|
* @param name the name of the field
|
||||||
* @param type the type of the field
|
|
||||||
* @return a resolved for the specified field
|
* @return a resolved for the specified field
|
||||||
*/
|
*/
|
||||||
public InjectedElementResolver field(String name, Class<?> type) {
|
public InjectedElementResolver field(String name) {
|
||||||
return new InjectedFieldResolver(getField(name, type), this.beanName);
|
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);
|
return new InjectedMethodResolver(getMethod(this.beanType, name, parameterTypes), this.beanType, this.beanName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Field getField(String fieldName, Class<?> fieldType) {
|
private Field getField(String fieldName) {
|
||||||
Field field = ReflectionUtils.findField(this.beanType, fieldName, fieldType);
|
Field field = ReflectionUtils.findField(this.beanType, fieldName);
|
||||||
Assert.notNull(field, () -> "No field '" + fieldName + "' with type " + fieldType.getName() + " found on " + this.beanType);
|
Assert.notNull(field, () -> "No field '" + fieldName + "' found on " + this.beanType.getName());
|
||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ class AutowiredAnnotationBeanInstantiationContributionTests {
|
||||||
void contributeWithPackageProtectedFieldInjection() {
|
void contributeWithPackageProtectedFieldInjection() {
|
||||||
CodeContribution contribution = contribute(PackageProtectedFieldInjectionSample.class);
|
CodeContribution contribution = contribute(PackageProtectedFieldInjectionSample.class);
|
||||||
assertThat(CodeSnippet.process(contribution.statements().toCodeBlock())).isEqualTo("""
|
assertThat(CodeSnippet.process(contribution.statements().toCodeBlock())).isEqualTo("""
|
||||||
instanceContext.field("environment", Environment.class)
|
instanceContext.field("environment")
|
||||||
.invoke(beanFactory, (attributes) -> bean.environment = attributes.get(0))""");
|
.invoke(beanFactory, (attributes) -> bean.environment = attributes.get(0))""");
|
||||||
assertThat(contribution.runtimeHints().reflection().typeHints()).singleElement().satisfies(typeHint -> {
|
assertThat(contribution.runtimeHints().reflection().typeHints()).singleElement().satisfies(typeHint -> {
|
||||||
assertThat(typeHint.getType()).isEqualTo(TypeReference.of(PackageProtectedFieldInjectionSample.class));
|
assertThat(typeHint.getType()).isEqualTo(TypeReference.of(PackageProtectedFieldInjectionSample.class));
|
||||||
|
|
@ -62,9 +62,9 @@ class AutowiredAnnotationBeanInstantiationContributionTests {
|
||||||
void contributeWithPrivateFieldInjection() {
|
void contributeWithPrivateFieldInjection() {
|
||||||
CodeContribution contribution = contribute(PrivateFieldInjectionSample.class);
|
CodeContribution contribution = contribute(PrivateFieldInjectionSample.class);
|
||||||
assertThat(CodeSnippet.process(contribution.statements().toCodeBlock())).isEqualTo("""
|
assertThat(CodeSnippet.process(contribution.statements().toCodeBlock())).isEqualTo("""
|
||||||
instanceContext.field("environment", Environment.class)
|
instanceContext.field("environment")
|
||||||
.invoke(beanFactory, (attributes) -> {
|
.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.makeAccessible(environmentField);
|
||||||
ReflectionUtils.setField(environmentField, bean, attributes.get(0));
|
ReflectionUtils.setField(environmentField, bean, attributes.get(0));
|
||||||
})""");
|
})""");
|
||||||
|
|
@ -99,9 +99,9 @@ class AutowiredAnnotationBeanInstantiationContributionTests {
|
||||||
void contributeWithInjectionPoints() {
|
void contributeWithInjectionPoints() {
|
||||||
CodeContribution contribution = contribute(ResourceInjectionBean.class);
|
CodeContribution contribution = contribute(ResourceInjectionBean.class);
|
||||||
assertThat(CodeSnippet.process(contribution.statements().toCodeBlock())).isEqualTo("""
|
assertThat(CodeSnippet.process(contribution.statements().toCodeBlock())).isEqualTo("""
|
||||||
instanceContext.field("testBean", TestBean.class)
|
instanceContext.field("testBean")
|
||||||
.resolve(beanFactory, false).ifResolved((attributes) -> {
|
.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.makeAccessible(testBeanField);
|
||||||
ReflectionUtils.setField(testBeanField, bean, attributes.get(0));
|
ReflectionUtils.setField(testBeanField, bean, attributes.get(0));
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ class InjectionGeneratorTests {
|
||||||
void generateInjectionForRequiredField() {
|
void generateInjectionForRequiredField() {
|
||||||
Field field = field(SampleBean.class, "counter");
|
Field field = field(SampleBean.class, "counter");
|
||||||
assertThat(generateInjection(field, true)).isEqualTo("""
|
assertThat(generateInjection(field, true)).isEqualTo("""
|
||||||
instanceContext.field("counter", Integer.class)
|
instanceContext.field("counter")
|
||||||
.invoke(beanFactory, (attributes) -> bean.counter = attributes.get(0))""");
|
.invoke(beanFactory, (attributes) -> bean.counter = attributes.get(0))""");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,7 +150,7 @@ class InjectionGeneratorTests {
|
||||||
void generateInjectionForNonRequiredField() {
|
void generateInjectionForNonRequiredField() {
|
||||||
Field field = field(SampleBean.class, "counter");
|
Field field = field(SampleBean.class, "counter");
|
||||||
assertThat(generateInjection(field, false)).isEqualTo("""
|
assertThat(generateInjection(field, false)).isEqualTo("""
|
||||||
instanceContext.field("counter", Integer.class)
|
instanceContext.field("counter")
|
||||||
.resolve(beanFactory, false).ifResolved((attributes) -> bean.counter = attributes.get(0))""");
|
.resolve(beanFactory, false).ifResolved((attributes) -> bean.counter = attributes.get(0))""");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,9 +158,9 @@ class InjectionGeneratorTests {
|
||||||
void generateInjectionForRequiredPrivateField() {
|
void generateInjectionForRequiredPrivateField() {
|
||||||
Field field = field(SampleBean.class, "source");
|
Field field = field(SampleBean.class, "source");
|
||||||
assertThat(generateInjection(field, true)).isEqualTo("""
|
assertThat(generateInjection(field, true)).isEqualTo("""
|
||||||
instanceContext.field("source", String.class)
|
instanceContext.field("source")
|
||||||
.invoke(beanFactory, (attributes) -> {
|
.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.makeAccessible(sourceField);
|
||||||
ReflectionUtils.setField(sourceField, bean, attributes.get(0));
|
ReflectionUtils.setField(sourceField, bean, attributes.get(0));
|
||||||
})""");
|
})""");
|
||||||
|
|
|
||||||
|
|
@ -257,8 +257,8 @@ class BeanDefinitionRegistrarTests {
|
||||||
beanFactory.registerSingleton("environment", environment);
|
beanFactory.registerSingleton("environment", environment);
|
||||||
BeanDefinitionRegistrar.of("test", InjectionSample.class).instanceSupplier(instanceContext -> {
|
BeanDefinitionRegistrar.of("test", InjectionSample.class).instanceSupplier(instanceContext -> {
|
||||||
InjectionSample bean = new InjectionSample();
|
InjectionSample bean = new InjectionSample();
|
||||||
instanceContext.field("environment", Environment.class).invoke(beanFactory,
|
instanceContext.field("environment").invoke(beanFactory, attributes ->
|
||||||
attributes -> bean.environment = (attributes.get(0)));
|
bean.environment = (attributes.get(0)));
|
||||||
return bean;
|
return bean;
|
||||||
}).register(beanFactory);
|
}).register(beanFactory);
|
||||||
assertBeanFactory(beanFactory, () -> {
|
assertBeanFactory(beanFactory, () -> {
|
||||||
|
|
@ -271,11 +271,10 @@ class BeanDefinitionRegistrarTests {
|
||||||
void registerWithInvalidField() {
|
void registerWithInvalidField() {
|
||||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||||
BeanDefinitionRegistrar.of("test", InjectionSample.class).instanceSupplier(instanceContext ->
|
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)
|
assertThatThrownBy(() -> beanFactory.getBean(InjectionSample.class)
|
||||||
).isInstanceOf(BeanCreationException.class)
|
).isInstanceOf(BeanCreationException.class).hasMessageContaining(
|
||||||
.hasMessageContaining("No field '%s' with type %s found", "doesNotExist", Object.class.getName())
|
"No field 'doesNotExist' found on " + InjectionSample.class.getName());
|
||||||
.hasMessageContaining(InjectionSample.class.getName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue