29
29
import java .beans .SimpleBeanInfo ;
30
30
import java .lang .reflect .Method ;
31
31
import java .lang .reflect .Modifier ;
32
- import java .util . Arrays ;
32
+ import java .lang . reflect . Type ;
33
33
import java .util .Collection ;
34
- import java .util .LinkedHashSet ;
35
- import java .util .Set ;
34
+ import java .util .LinkedHashMap ;
35
+ import java .util .Map ;
36
36
37
37
import org .springframework .beans .BeanInfoFactory ;
38
38
import org .springframework .beans .BeanUtils ;
39
39
import org .springframework .core .KotlinDetector ;
40
40
import org .springframework .core .Ordered ;
41
+ import org .springframework .lang .Nullable ;
42
+ import org .springframework .util .ClassUtils ;
43
+ import org .springframework .util .ReflectionUtils ;
44
+ import org .springframework .util .StringUtils ;
41
45
42
46
/**
43
47
* {@link BeanInfoFactory} specific to Kotlin types using Kotlin reflection to determine bean properties.
@@ -62,7 +66,7 @@ public BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException {
62
66
63
67
KClass <?> kotlinClass = JvmClassMappingKt .getKotlinClass (beanClass );
64
68
Collection <KCallable <?>> members = kotlinClass .getMembers ();
65
- Set < PropertyDescriptor > pds = new LinkedHashSet <>(members .size ());
69
+ Map < String , PropertyDescriptor > descriptors = new LinkedHashMap <>(members .size (), 1.f );
66
70
67
71
for (KCallable <?> member : members ) {
68
72
@@ -71,6 +75,16 @@ public BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException {
71
75
Method getter = ReflectJvmMapping .getJavaGetter (property );
72
76
Method setter = property instanceof KMutableProperty <?> kmp ? ReflectJvmMapping .getJavaSetter (kmp ) : null ;
73
77
78
+ if (getter == null ) {
79
+ Type javaType = ReflectJvmMapping .getJavaType (property .getReturnType ());
80
+ getter = ReflectionUtils .findMethod (beanClass ,
81
+ javaType == Boolean .TYPE ? "is" : "get" + StringUtils .capitalize (property .getName ()));
82
+ }
83
+
84
+ if (getter != null ) {
85
+ getter = ClassUtils .getMostSpecificMethod (getter , beanClass );
86
+ }
87
+
74
88
if (getter != null && (Modifier .isStatic (getter .getModifiers ()) || getter .getParameterCount () != 0 )) {
75
89
continue ;
76
90
}
@@ -82,7 +96,7 @@ public BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException {
82
96
}
83
97
}
84
98
85
- pds . add ( new PropertyDescriptor (property .getName (), getter , setter ));
99
+ descriptors . put ( property . getName (), new PropertyDescriptor (property .getName (), getter , setter ));
86
100
}
87
101
}
88
102
@@ -95,9 +109,17 @@ public BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException {
95
109
if (javaClass != Object .class ) {
96
110
97
111
PropertyDescriptor [] javaPropertyDescriptors = BeanUtils .getPropertyDescriptors (javaClass );
98
- pds .addAll (Arrays .asList (javaPropertyDescriptors ));
112
+
113
+ for (PropertyDescriptor descriptor : javaPropertyDescriptors ) {
114
+
115
+ descriptor = new PropertyDescriptor (descriptor .getName (), specialize (beanClass , descriptor .getReadMethod ()),
116
+ specialize (beanClass , descriptor .getWriteMethod ()));
117
+ descriptors .put (descriptor .getName (), descriptor );
118
+ }
99
119
}
100
120
121
+ PropertyDescriptor [] propertyDescriptors = descriptors .values ().toArray (new PropertyDescriptor [0 ]);
122
+
101
123
return new SimpleBeanInfo () {
102
124
@ Override
103
125
public BeanDescriptor getBeanDescriptor () {
@@ -106,11 +128,21 @@ public BeanDescriptor getBeanDescriptor() {
106
128
107
129
@ Override
108
130
public PropertyDescriptor [] getPropertyDescriptors () {
109
- return pds . toArray ( new PropertyDescriptor [ 0 ]) ;
131
+ return propertyDescriptors ;
110
132
}
111
133
};
112
134
}
113
135
136
+ @ Nullable
137
+ private static Method specialize (Class <?> beanClass , @ Nullable Method method ) {
138
+
139
+ if (method == null ) {
140
+ return method ;
141
+ }
142
+
143
+ return ClassUtils .getMostSpecificMethod (method , beanClass );
144
+ }
145
+
114
146
@ Override
115
147
public int getOrder () {
116
148
return LOWEST_PRECEDENCE - 10 ; // leave some space for customizations.
0 commit comments