|
16 | 16 |
|
17 | 17 | package org.springframework.beans.factory.aot;
|
18 | 18 |
|
| 19 | +import java.beans.BeanInfo; |
| 20 | +import java.beans.IntrospectionException; |
| 21 | +import java.beans.Introspector; |
| 22 | +import java.beans.PropertyDescriptor; |
19 | 23 | import java.lang.reflect.Method;
|
| 24 | +import java.util.Arrays; |
| 25 | +import java.util.Collections; |
| 26 | +import java.util.HashMap; |
20 | 27 | import java.util.Map;
|
21 | 28 | import java.util.Objects;
|
22 | 29 | import java.util.function.BiFunction;
|
23 | 30 | import java.util.function.BiPredicate;
|
| 31 | +import java.util.function.Consumer; |
24 | 32 | import java.util.function.Function;
|
25 | 33 | import java.util.function.Predicate;
|
26 | 34 |
|
27 | 35 | import org.springframework.aot.generate.MethodGenerator;
|
| 36 | +import org.springframework.aot.hint.ExecutableHint; |
| 37 | +import org.springframework.aot.hint.ExecutableMode; |
28 | 38 | import org.springframework.aot.hint.RuntimeHints;
|
| 39 | +import org.springframework.beans.BeanInfoFactory; |
| 40 | +import org.springframework.beans.ExtendedBeanInfoFactory; |
29 | 41 | import org.springframework.beans.MutablePropertyValues;
|
30 | 42 | import org.springframework.beans.PropertyValue;
|
31 | 43 | import org.springframework.beans.factory.config.BeanDefinition;
|
|
36 | 48 | import org.springframework.beans.factory.support.RootBeanDefinition;
|
37 | 49 | import org.springframework.javapoet.CodeBlock;
|
38 | 50 | import org.springframework.javapoet.CodeBlock.Builder;
|
| 51 | +import org.springframework.lang.Nullable; |
39 | 52 | import org.springframework.util.ClassUtils;
|
40 | 53 | import org.springframework.util.ObjectUtils;
|
41 | 54 | import org.springframework.util.ReflectionUtils;
|
@@ -69,6 +82,9 @@ class BeanDefinitionPropertiesCodeGenerator {
|
69 | 82 |
|
70 | 83 | private static final String BEAN_DEFINITION_VARIABLE = BeanRegistrationCodeFragments.BEAN_DEFINITION_VARIABLE;
|
71 | 84 |
|
| 85 | + private static final Consumer<ExecutableHint.Builder> INVOKE_HINT = hint -> hint.withMode(ExecutableMode.INVOKE); |
| 86 | + |
| 87 | + private static final BeanInfoFactory beanInfoFactory = new ExtendedBeanInfoFactory(); |
72 | 88 |
|
73 | 89 | private final RuntimeHints hints;
|
74 | 90 |
|
@@ -125,14 +141,14 @@ private void addInitDestroyMethods(Builder builder,
|
125 | 141 | AbstractBeanDefinition beanDefinition, String[] methodNames, String format) {
|
126 | 142 |
|
127 | 143 | if (!ObjectUtils.isEmpty(methodNames)) {
|
128 |
| - Class<?> beanUserClass = ClassUtils |
| 144 | + Class<?> beanType = ClassUtils |
129 | 145 | .getUserClass(beanDefinition.getResolvableType().toClass());
|
130 | 146 | Builder arguments = CodeBlock.builder();
|
131 | 147 | for (int i = 0; i < methodNames.length; i++) {
|
132 | 148 | String methodName = methodNames[i];
|
133 | 149 | if (!AbstractBeanDefinition.INFER_METHOD.equals(methodName)) {
|
134 | 150 | arguments.add((i != 0) ? ", $S" : "$S", methodName);
|
135 |
| - addInitDestroyHint(beanUserClass, methodName); |
| 151 | + addInitDestroyHint(beanType, methodName); |
136 | 152 | }
|
137 | 153 | }
|
138 | 154 | builder.addStatement(format, BEAN_DEFINITION_VARIABLE, arguments.build());
|
@@ -181,9 +197,53 @@ private void addPropertyValues(CodeBlock.Builder builder,
|
181 | 197 | builder.addStatement("$L.getPropertyValues().addPropertyValue($S, $L)",
|
182 | 198 | BEAN_DEFINITION_VARIABLE, propertyValue.getName(), code);
|
183 | 199 | }
|
| 200 | + Class<?> beanType = ClassUtils |
| 201 | + .getUserClass(beanDefinition.getResolvableType().toClass()); |
| 202 | + BeanInfo beanInfo = (beanType != Object.class) ? getBeanInfo(beanType) : null; |
| 203 | + if (beanInfo != null) { |
| 204 | + Map<String, Method> writeMethods = getWriteMethods(beanInfo); |
| 205 | + for (PropertyValue propertyValue : propertyValues) { |
| 206 | + Method writeMethod = writeMethods.get(propertyValue.getName()); |
| 207 | + if (writeMethod != null) { |
| 208 | + this.hints.reflection().registerMethod(writeMethod, INVOKE_HINT); |
| 209 | + } |
| 210 | + } |
| 211 | + } |
184 | 212 | }
|
185 | 213 | }
|
186 | 214 |
|
| 215 | + @Nullable |
| 216 | + private BeanInfo getBeanInfo(Class<?> beanType) { |
| 217 | + try { |
| 218 | + BeanInfo beanInfo = beanInfoFactory.getBeanInfo(beanType); |
| 219 | + if (beanInfo != null) { |
| 220 | + return beanInfo; |
| 221 | + } |
| 222 | + return Introspector.getBeanInfo(beanType, Introspector.IGNORE_ALL_BEANINFO); |
| 223 | + } |
| 224 | + catch (IntrospectionException ex) { |
| 225 | + return null; |
| 226 | + } |
| 227 | + } |
| 228 | + |
| 229 | + private Map<String, Method> getWriteMethods(BeanInfo beanInfo) { |
| 230 | + Map<String, Method> writeMethods = new HashMap<>(); |
| 231 | + for (PropertyDescriptor propertyDescriptor : beanInfo.getPropertyDescriptors()) { |
| 232 | + writeMethods.put(propertyDescriptor.getName(), |
| 233 | + propertyDescriptor.getWriteMethod()); |
| 234 | + } |
| 235 | + return Collections.unmodifiableMap(writeMethods); |
| 236 | + } |
| 237 | + |
| 238 | + @Nullable |
| 239 | + private Method findWriteMethod(BeanInfo beanInfo, String propertyName) { |
| 240 | + return Arrays.stream(beanInfo.getPropertyDescriptors()) |
| 241 | + .filter(pd -> propertyName.equals(pd.getName())) |
| 242 | + .map(java.beans.PropertyDescriptor::getWriteMethod) |
| 243 | + .filter(Objects::nonNull).findFirst().orElse(null); |
| 244 | + } |
| 245 | + |
| 246 | + |
187 | 247 | private void addAttributes(CodeBlock.Builder builder, BeanDefinition beanDefinition) {
|
188 | 248 | String[] attributeNames = beanDefinition.attributeNames();
|
189 | 249 | if (!ObjectUtils.isEmpty(attributeNames)) {
|
|
0 commit comments