1
+ /*
2
+ * Copyright 2002-2011 the original author or authors.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ package org .springframework .core .convert ;
17
+
18
+ import java .beans .PropertyDescriptor ;
19
+ import java .lang .annotation .Annotation ;
20
+ import java .lang .reflect .Field ;
21
+ import java .lang .reflect .Method ;
22
+ import java .util .LinkedHashMap ;
23
+ import java .util .Map ;
24
+
25
+ import org .springframework .core .GenericCollectionTypeResolver ;
26
+ import org .springframework .core .GenericTypeResolver ;
27
+ import org .springframework .core .MethodParameter ;
28
+ import org .springframework .util .ReflectionUtils ;
29
+ import org .springframework .util .StringUtils ;
30
+
31
+ class BeanPropertyDescriptor extends AbstractDescriptor {
32
+
33
+ private final Class <?> beanClass ;
34
+
35
+ private final PropertyDescriptor property ;
36
+
37
+ private final MethodParameter methodParameter ;
38
+
39
+ private final Annotation [] annotations ;
40
+
41
+ public BeanPropertyDescriptor (Class <?> beanClass , PropertyDescriptor property ) {
42
+ super (property .getPropertyType ());
43
+ this .beanClass = beanClass ;
44
+ this .property = property ;
45
+ this .methodParameter = resolveMethodParameter ();
46
+ this .annotations = resolveAnnotations ();
47
+ }
48
+
49
+ @ Override
50
+ public Annotation [] getAnnotations () {
51
+ return annotations ;
52
+ }
53
+
54
+ @ Override
55
+ protected Class <?> getCollectionElementClass () {
56
+ return GenericCollectionTypeResolver .getCollectionParameterType (methodParameter );
57
+ }
58
+
59
+ @ Override
60
+ protected Class <?> getMapKeyClass () {
61
+ return GenericCollectionTypeResolver .getMapKeyParameterType (methodParameter );
62
+ }
63
+
64
+ @ Override
65
+ protected Class <?> getMapValueClass () {
66
+ return GenericCollectionTypeResolver .getMapValueParameterType (methodParameter );
67
+ }
68
+
69
+ @ Override
70
+ protected AbstractDescriptor nested (Class <?> type , int typeIndex ) {
71
+ MethodParameter methodParameter = new MethodParameter (this .methodParameter );
72
+ methodParameter .increaseNestingLevel ();
73
+ methodParameter .setTypeIndexForCurrentLevel (typeIndex );
74
+ return new BeanPropertyDescriptor (type , beanClass , property , methodParameter , annotations );
75
+ }
76
+
77
+ // internal
78
+
79
+ private MethodParameter resolveMethodParameter () {
80
+ MethodParameter parameter = parameterForPropertyMethod ();
81
+ // needed to resolve generic property types that parameterized by sub-classes e.g. T getFoo();
82
+ GenericTypeResolver .resolveParameterType (parameter , beanClass );
83
+ return parameter ;
84
+ }
85
+
86
+ private MethodParameter parameterForPropertyMethod () {
87
+ if (property .getReadMethod () != null ) {
88
+ return new MethodParameter (property .getReadMethod (), -1 );
89
+ } else if (property .getWriteMethod () != null ) {
90
+ return new MethodParameter (property .getWriteMethod (), 0 );
91
+ } else {
92
+ throw new IllegalArgumentException ("Property is neither readable or writeable" );
93
+ }
94
+ }
95
+
96
+ private Annotation [] resolveAnnotations () {
97
+ Map <Class <?>, Annotation > annMap = new LinkedHashMap <Class <?>, Annotation >();
98
+ Method readMethod = this .property .getReadMethod ();
99
+ if (readMethod != null ) {
100
+ for (Annotation ann : readMethod .getAnnotations ()) {
101
+ annMap .put (ann .annotationType (), ann );
102
+ }
103
+ }
104
+ Method writeMethod = this .property .getWriteMethod ();
105
+ if (writeMethod != null ) {
106
+ for (Annotation ann : writeMethod .getAnnotations ()) {
107
+ annMap .put (ann .annotationType (), ann );
108
+ }
109
+ }
110
+ Field field = getField ();
111
+ if (field != null ) {
112
+ for (Annotation ann : field .getAnnotations ()) {
113
+ annMap .put (ann .annotationType (), ann );
114
+ }
115
+ }
116
+ return annMap .values ().toArray (new Annotation [annMap .size ()]);
117
+ }
118
+
119
+ private Field getField () {
120
+ String name = this .property .getName ();
121
+ if (!StringUtils .hasLength (name )) {
122
+ return null ;
123
+ }
124
+ Class <?> declaringClass = declaringClass ();
125
+ Field field = ReflectionUtils .findField (declaringClass , name );
126
+ if (field == null ) {
127
+ // Same lenient fallback checking as in CachedIntrospectionResults...
128
+ field = ReflectionUtils .findField (declaringClass , name .substring (0 , 1 ).toLowerCase () + name .substring (1 ));
129
+ if (field == null ) {
130
+ field = ReflectionUtils .findField (declaringClass , name .substring (0 , 1 ).toUpperCase () + name .substring (1 ));
131
+ }
132
+ }
133
+ return field ;
134
+ }
135
+
136
+ private Class <?> declaringClass () {
137
+ if (this .property .getReadMethod () != null ) {
138
+ return this .property .getReadMethod ().getDeclaringClass ();
139
+ } else {
140
+ return this .property .getWriteMethod ().getDeclaringClass ();
141
+ }
142
+ }
143
+
144
+ private BeanPropertyDescriptor (Class <?> type , Class <?> beanClass , java .beans .PropertyDescriptor propertyDescriptor , MethodParameter methodParameter , Annotation [] annotations ) {
145
+ super (type );
146
+ this .beanClass = beanClass ;
147
+ this .property = propertyDescriptor ;
148
+ this .methodParameter = methodParameter ;
149
+ this .annotations = annotations ;
150
+ }
151
+
152
+ }
0 commit comments