|
16 | 16 |
|
17 | 17 | package org.springframework.boot.context.properties;
|
18 | 18 |
|
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; |
26 | 19 | import java.util.ArrayList;
|
27 |
| -import java.util.Arrays; |
28 |
| -import java.util.Collection; |
29 |
| -import java.util.HashSet; |
30 | 20 | import java.util.List;
|
31 |
| -import java.util.Map; |
32 |
| -import java.util.Set; |
33 | 21 |
|
34 | 22 | import org.springframework.aot.generate.GenerationContext;
|
35 |
| -import org.springframework.aot.hint.MemberCategory; |
36 |
| -import org.springframework.aot.hint.RuntimeHints; |
37 | 23 | import org.springframework.aot.hint.support.RuntimeHintsUtils;
|
38 |
| -import org.springframework.beans.BeanInfoFactory; |
39 |
| -import org.springframework.beans.ExtendedBeanInfoFactory; |
40 | 24 | import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;
|
41 | 25 | import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;
|
42 | 26 | import org.springframework.beans.factory.aot.BeanFactoryInitializationCode;
|
43 | 27 | 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; |
47 | 28 | import org.springframework.util.ClassUtils;
|
48 | 29 | import org.springframework.util.CollectionUtils;
|
49 |
| -import org.springframework.util.ReflectionUtils; |
50 | 30 |
|
51 | 31 | /**
|
52 | 32 | * {@link BeanFactoryInitializationAotProcessor} that contributes runtime hints for
|
@@ -89,177 +69,8 @@ public void applyTo(GenerationContext generationContext,
|
89 | 69 | BeanFactoryInitializationCode beanFactoryInitializationCode) {
|
90 | 70 | RuntimeHintsUtils.registerAnnotation(generationContext.getRuntimeHints(), ConfigurationProperties.class);
|
91 | 71 | 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()); |
263 | 74 | }
|
264 | 75 | }
|
265 | 76 |
|
|
0 commit comments