Register bean reflection hint for property fields
Prior to this commit, the bean definition properties code generator would register hints for invoking the setter methods of registered property values defined for the bean definition. The internal algorithm is also reflecting on the Field to discover annotations. Doing so actually calls `getDeclaredFields` to iterate on the available fields. This is done recursively up the type hierarchy until the field is found. This commit registers the required reflection metadata. Closes gh-31390
This commit is contained in:
		
							parent
							
								
									30a94b041f
								
							
						
					
					
						commit
						8064659136
					
				|  | @ -34,6 +34,7 @@ import java.util.function.Predicate; | ||||||
| 
 | 
 | ||||||
| import org.springframework.aot.generate.GeneratedMethods; | import org.springframework.aot.generate.GeneratedMethods; | ||||||
| import org.springframework.aot.hint.ExecutableMode; | import org.springframework.aot.hint.ExecutableMode; | ||||||
|  | import org.springframework.aot.hint.MemberCategory; | ||||||
| import org.springframework.aot.hint.RuntimeHints; | import org.springframework.aot.hint.RuntimeHints; | ||||||
| import org.springframework.aot.hint.TypeReference; | import org.springframework.aot.hint.TypeReference; | ||||||
| import org.springframework.beans.BeanUtils; | import org.springframework.beans.BeanUtils; | ||||||
|  | @ -195,6 +196,13 @@ class BeanDefinitionPropertiesCodeGenerator { | ||||||
| 					Method writeMethod = writeMethods.get(propertyValue.getName()); | 					Method writeMethod = writeMethods.get(propertyValue.getName()); | ||||||
| 					if (writeMethod != null) { | 					if (writeMethod != null) { | ||||||
| 						this.hints.reflection().registerMethod(writeMethod, ExecutableMode.INVOKE); | 						this.hints.reflection().registerMethod(writeMethod, ExecutableMode.INVOKE); | ||||||
|  | 						// ReflectionUtils#findField searches recursively in the type hierarchy | ||||||
|  | 						Class<?> searchType = beanDefinition.getTargetType(); | ||||||
|  | 						while (searchType != null && searchType != writeMethod.getDeclaringClass()) { | ||||||
|  | 							this.hints.reflection().registerType(searchType, MemberCategory.DECLARED_FIELDS); | ||||||
|  | 							searchType = searchType.getSuperclass(); | ||||||
|  | 						} | ||||||
|  | 						this.hints.reflection().registerType(writeMethod.getDeclaringClass(), MemberCategory.DECLARED_FIELDS); | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | @ -34,6 +34,7 @@ import org.junit.jupiter.api.Test; | ||||||
| import org.reactivestreams.Publisher; | import org.reactivestreams.Publisher; | ||||||
| 
 | 
 | ||||||
| import org.springframework.aot.generate.GeneratedClass; | import org.springframework.aot.generate.GeneratedClass; | ||||||
|  | import org.springframework.aot.hint.MemberCategory; | ||||||
| import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; | import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; | ||||||
| import org.springframework.aot.test.generate.TestGenerationContext; | import org.springframework.aot.test.generate.TestGenerationContext; | ||||||
| import org.springframework.beans.factory.FactoryBean; | import org.springframework.beans.factory.FactoryBean; | ||||||
|  | @ -240,6 +241,21 @@ class BeanDefinitionPropertiesCodeGeneratorTests { | ||||||
| 			assertThat(actual.getPropertyValues().get("spring")).isEqualTo("framework"); | 			assertThat(actual.getPropertyValues().get("spring")).isEqualTo("framework"); | ||||||
| 		}); | 		}); | ||||||
| 		assertHasMethodInvokeHints(PropertyValuesBean.class, "setTest", "setSpring"); | 		assertHasMethodInvokeHints(PropertyValuesBean.class, "setTest", "setSpring"); | ||||||
|  | 		assertHasDecalredFieldsHint(PropertyValuesBean.class); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test | ||||||
|  | 	void propertyValuesWhenValuesOnParentClass() { | ||||||
|  | 		this.beanDefinition.setTargetType(ExtendedPropertyValuesBean.class); | ||||||
|  | 		this.beanDefinition.getPropertyValues().add("test", String.class); | ||||||
|  | 		this.beanDefinition.getPropertyValues().add("spring", "framework"); | ||||||
|  | 		compile((actual, compiled) -> { | ||||||
|  | 			assertThat(actual.getPropertyValues().get("test")).isEqualTo(String.class); | ||||||
|  | 			assertThat(actual.getPropertyValues().get("spring")).isEqualTo("framework"); | ||||||
|  | 		}); | ||||||
|  | 		assertHasMethodInvokeHints(PropertyValuesBean.class, "setTest", "setSpring"); | ||||||
|  | 		assertHasDecalredFieldsHint(ExtendedPropertyValuesBean.class); | ||||||
|  | 		assertHasDecalredFieldsHint(PropertyValuesBean.class); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
|  | @ -300,6 +316,7 @@ class BeanDefinitionPropertiesCodeGeneratorTests { | ||||||
| 			assertThat(actual.getPropertyValues().get("name")).isEqualTo("World"); | 			assertThat(actual.getPropertyValues().get("name")).isEqualTo("World"); | ||||||
| 		}); | 		}); | ||||||
| 		assertHasMethodInvokeHints(PropertyValuesFactoryBean.class, "setPrefix", "setName" ); | 		assertHasMethodInvokeHints(PropertyValuesFactoryBean.class, "setPrefix", "setName" ); | ||||||
|  | 		assertHasDecalredFieldsHint(PropertyValuesFactoryBean.class); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
|  | @ -453,6 +470,12 @@ class BeanDefinitionPropertiesCodeGeneratorTests { | ||||||
| 			.test(this.generationContext.getRuntimeHints())); | 			.test(this.generationContext.getRuntimeHints())); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	private void assertHasDecalredFieldsHint(Class<?> beanType) { | ||||||
|  | 		assertThat(RuntimeHintsPredicates.reflection() | ||||||
|  | 				.onType(beanType).withMemberCategory(MemberCategory.DECLARED_FIELDS)) | ||||||
|  | 				.accepts(this.generationContext.getRuntimeHints()); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	private void compile(BiConsumer<RootBeanDefinition, Compiled> result) { | 	private void compile(BiConsumer<RootBeanDefinition, Compiled> result) { | ||||||
| 		compile(attribute -> true, result); | 		compile(attribute -> true, result); | ||||||
| 	} | 	} | ||||||
|  | @ -524,6 +547,10 @@ class BeanDefinitionPropertiesCodeGeneratorTests { | ||||||
| 
 | 
 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	static class ExtendedPropertyValuesBean extends PropertyValuesBean { | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	static class PropertyValuesFactoryBean implements FactoryBean<String> { | 	static class PropertyValuesFactoryBean implements FactoryBean<String> { | ||||||
| 
 | 
 | ||||||
| 		private String prefix; | 		private String prefix; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue