Skip to content

Commit 55bb921

Browse files
committed
Extract TypeProcessor into separate class
1 parent 0291388 commit 55bb921

File tree

2 files changed

+222
-191
lines changed

2 files changed

+222
-191
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanFactoryInitializationAotProcessor.java

Lines changed: 2 additions & 191 deletions
Original file line numberDiff line numberDiff line change
@@ -16,37 +16,17 @@
1616

1717
package org.springframework.boot.context.properties;
1818

19-
import java.beans.BeanInfo;
20-
import java.beans.IntrospectionException;
21-
import java.beans.Introspector;
22-
import java.beans.PropertyDescriptor;
23-
import java.lang.reflect.Constructor;
24-
import java.lang.reflect.Field;
25-
import java.lang.reflect.Method;
2619
import java.util.ArrayList;
27-
import java.util.Arrays;
28-
import java.util.Collection;
29-
import java.util.HashSet;
3020
import java.util.List;
31-
import java.util.Map;
32-
import java.util.Set;
3321

3422
import org.springframework.aot.generate.GenerationContext;
35-
import org.springframework.aot.hint.MemberCategory;
36-
import org.springframework.aot.hint.RuntimeHints;
3723
import org.springframework.aot.hint.support.RuntimeHintsUtils;
38-
import org.springframework.beans.BeanInfoFactory;
39-
import org.springframework.beans.ExtendedBeanInfoFactory;
4024
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;
4125
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;
4226
import org.springframework.beans.factory.aot.BeanFactoryInitializationCode;
4327
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
44-
import org.springframework.boot.context.properties.bind.Bindable;
45-
import org.springframework.core.ResolvableType;
46-
import org.springframework.core.annotation.MergedAnnotations;
4728
import org.springframework.util.ClassUtils;
4829
import org.springframework.util.CollectionUtils;
49-
import org.springframework.util.ReflectionUtils;
5030

5131
/**
5232
* {@link BeanFactoryInitializationAotProcessor} that contributes runtime hints for
@@ -89,177 +69,8 @@ public void applyTo(GenerationContext generationContext,
8969
BeanFactoryInitializationCode beanFactoryInitializationCode) {
9070
RuntimeHintsUtils.registerAnnotation(generationContext.getRuntimeHints(), ConfigurationProperties.class);
9171
for (Class<?> type : this.types) {
92-
TypeProcessor.processConfigurationProperties(type, generationContext.getRuntimeHints());
93-
}
94-
}
95-
96-
}
97-
98-
/**
99-
* Process a given type for binding purposes, discovering any nested type it may
100-
* expose via a property.
101-
*/
102-
private static final class TypeProcessor {
103-
104-
private static final BeanInfoFactory beanInfoFactory = new ExtendedBeanInfoFactory();
105-
106-
private final Class<?> type;
107-
108-
private final Constructor<?> bindConstructor;
109-
110-
private final BeanInfo beanInfo;
111-
112-
private final Set<Class<?>> seen;
113-
114-
private TypeProcessor(Class<?> type, Constructor<?> bindConstructor, Set<Class<?>> seen) {
115-
this.type = type;
116-
this.bindConstructor = bindConstructor;
117-
this.beanInfo = getBeanInfo(type);
118-
this.seen = seen;
119-
}
120-
121-
private static void processConfigurationProperties(Class<?> type, RuntimeHints runtimeHints) {
122-
new TypeProcessor(type, getBindConstructor(type, false), new HashSet<>()).process(runtimeHints);
123-
}
124-
125-
private void processNestedType(Class<?> type, RuntimeHints runtimeHints) {
126-
processNestedType(type, getBindConstructor(type, true), runtimeHints);
127-
}
128-
129-
private void processNestedType(Class<?> type, Constructor<?> bindConstructor, RuntimeHints runtimeHints) {
130-
new TypeProcessor(type, bindConstructor, this.seen).process(runtimeHints);
131-
}
132-
133-
private static Constructor<?> getBindConstructor(Class<?> type, boolean nestedType) {
134-
Bindable<?> bindable = Bindable.of(type);
135-
return ConfigurationPropertiesBindConstructorProvider.INSTANCE.getBindConstructor(bindable, nestedType);
136-
}
137-
138-
private void process(RuntimeHints runtimeHints) {
139-
if (this.seen.contains(this.type)) {
140-
return;
141-
}
142-
this.seen.add(this.type);
143-
runtimeHints.reflection().registerType(this.type, (hint) -> hint
144-
.withMembers(MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.INVOKE_PUBLIC_METHODS));
145-
handleConstructor(runtimeHints);
146-
if (this.bindConstructor != null) {
147-
handleValueObjectProperties(runtimeHints);
148-
}
149-
else if (this.beanInfo != null) {
150-
handleJavaBeanProperties(runtimeHints);
151-
}
152-
}
153-
154-
private void handleConstructor(RuntimeHints runtimeHints) {
155-
if (this.bindConstructor != null) {
156-
runtimeHints.reflection().registerConstructor(this.bindConstructor);
157-
}
158-
else {
159-
Arrays.stream(this.type.getDeclaredConstructors())
160-
.filter((candidate) -> candidate.getParameterCount() == 0).findFirst()
161-
.ifPresent((constructor) -> runtimeHints.reflection().registerConstructor(constructor));
162-
}
163-
}
164-
165-
private void handleValueObjectProperties(RuntimeHints runtimeHints) {
166-
for (int i = 0; i < this.bindConstructor.getParameterCount(); i++) {
167-
String propertyName = this.bindConstructor.getParameters()[i].getName();
168-
ResolvableType propertyType = ResolvableType.forConstructorParameter(this.bindConstructor, i);
169-
handleProperty(runtimeHints, propertyName, propertyType);
170-
}
171-
}
172-
173-
private void handleJavaBeanProperties(RuntimeHints runtimeHints) {
174-
for (PropertyDescriptor propertyDescriptor : this.beanInfo.getPropertyDescriptors()) {
175-
Method readMethod = propertyDescriptor.getReadMethod();
176-
if (readMethod != null) {
177-
ResolvableType propertyType = ResolvableType.forMethodReturnType(readMethod, this.type);
178-
String propertyName = propertyDescriptor.getName();
179-
if (isSetterMandatory(propertyName, propertyType) && propertyDescriptor.getWriteMethod() == null) {
180-
continue;
181-
}
182-
handleProperty(runtimeHints, propertyName, propertyType);
183-
}
184-
}
185-
}
186-
187-
private void handleProperty(RuntimeHints runtimeHints, String propertyName, ResolvableType propertyType) {
188-
Class<?> propertyClass = propertyType.resolve();
189-
if (propertyClass == null) {
190-
return;
191-
}
192-
if (propertyClass.equals(this.type)) {
193-
return; // Prevent infinite recursion
194-
}
195-
Class<?> componentType = getComponentType(propertyType);
196-
if (componentType != null) {
197-
// Can be a list of simple types
198-
if (!isJavaType(componentType)) {
199-
processNestedType(componentType, runtimeHints);
200-
}
201-
}
202-
else if (isNestedType(propertyName, propertyClass)) {
203-
processNestedType(propertyClass, runtimeHints);
204-
}
205-
}
206-
207-
private boolean isSetterMandatory(String propertyName, ResolvableType propertyType) {
208-
Class<?> propertyClass = propertyType.resolve();
209-
if (propertyClass == null) {
210-
return true;
211-
}
212-
if (getComponentType(propertyType) != null) {
213-
return false;
214-
}
215-
return !isNestedType(propertyName, propertyClass);
216-
}
217-
218-
private Class<?> getComponentType(ResolvableType propertyType) {
219-
Class<?> propertyClass = propertyType.toClass();
220-
if (propertyType.isArray()) {
221-
return propertyType.getComponentType().toClass();
222-
}
223-
else if (Collection.class.isAssignableFrom(propertyClass)) {
224-
return propertyType.as(Collection.class).getGeneric(0).toClass();
225-
}
226-
else if (Map.class.isAssignableFrom(propertyClass)) {
227-
return propertyType.as(Map.class).getGeneric(1).toClass();
228-
}
229-
return null;
230-
}
231-
232-
/**
233-
* Specify whether the specified property refer to a nested type. A nested type
234-
* represents a sub-namespace that need to be fully resolved.
235-
* @param propertyName the name of the property
236-
* @param propertyType the type of the property
237-
* @return whether the specified {@code propertyType} is a nested type
238-
*/
239-
private boolean isNestedType(String propertyName, Class<?> propertyType) {
240-
if (this.type.equals(propertyType.getDeclaringClass())) {
241-
return true;
242-
}
243-
else {
244-
Field field = ReflectionUtils.findField(this.type, propertyName);
245-
return field != null && MergedAnnotations.from(field).isPresent(NestedConfigurationProperty.class);
246-
}
247-
}
248-
249-
private boolean isJavaType(Class<?> candidate) {
250-
return candidate.getPackageName().startsWith("java.");
251-
}
252-
253-
private static BeanInfo getBeanInfo(Class<?> beanType) {
254-
try {
255-
BeanInfo beanInfo = beanInfoFactory.getBeanInfo(beanType);
256-
if (beanInfo != null) {
257-
return beanInfo;
258-
}
259-
return Introspector.getBeanInfo(beanType, Introspector.IGNORE_ALL_BEANINFO);
260-
}
261-
catch (IntrospectionException ex) {
262-
return null;
72+
ConfigurationPropertiesReflectionHintsRegistrar.processConfigurationProperties(type,
73+
generationContext.getRuntimeHints().reflection());
26374
}
26475
}
26576

0 commit comments

Comments
 (0)