Skip to content

Commit cfb3873

Browse files
author
Keith Donald
committed
broke out to top-level class for readability
1 parent c09227a commit cfb3873

File tree

6 files changed

+214
-168
lines changed

6 files changed

+214
-168
lines changed

org.springframework.beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@
4242
import org.springframework.core.MethodParameter;
4343
import org.springframework.core.convert.ConversionException;
4444
import org.springframework.core.convert.ConverterNotFoundException;
45+
import org.springframework.core.convert.Property;
4546
import org.springframework.core.convert.TypeDescriptor;
46-
import org.springframework.core.convert.TypeDescriptor.Property;
4747
import org.springframework.util.Assert;
4848
import org.springframework.util.ObjectUtils;
4949
import org.springframework.util.StringUtils;

org.springframework.core/src/main/java/org/springframework/core/convert/BeanPropertyDescriptor.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
import org.springframework.core.GenericCollectionTypeResolver;
2121
import org.springframework.core.MethodParameter;
22-
import org.springframework.core.convert.TypeDescriptor.Property;
2322

2423
class BeanPropertyDescriptor extends AbstractDescriptor {
2524

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
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.lang.annotation.Annotation;
19+
import java.lang.reflect.Field;
20+
import java.lang.reflect.Method;
21+
import java.util.LinkedHashMap;
22+
import java.util.Map;
23+
24+
import org.springframework.core.GenericTypeResolver;
25+
import org.springframework.core.MethodParameter;
26+
import org.springframework.util.ReflectionUtils;
27+
import org.springframework.util.StringUtils;
28+
29+
/**
30+
* A description of a JavaBeans Property that allows us to avoid a dependency on java.beans.PropertyDescriptor.
31+
* java.beans is not available in a number of environments (e.g. Android, Java ME), so this is desirable.
32+
* Used to build a TypeDescriptor from a property location.
33+
* The built TypeDescriptor can then be used to convert from/to the property type.
34+
* @author Keith Donald
35+
* @see TypeDescriptor#TypeDescriptor(Property)
36+
* @see TypeDescriptor#nested(Property, int)
37+
*/
38+
public final class Property {
39+
40+
private final Class<?> objectType;
41+
42+
private final Method readMethod;
43+
44+
private final Method writeMethod;
45+
46+
private final String name;
47+
48+
private final MethodParameter methodParameter;
49+
50+
private final Annotation[] annotations;
51+
52+
public Property(Class<?> objectType, Method readMethod, Method writeMethod) {
53+
this.objectType = objectType;
54+
this.readMethod = readMethod;
55+
this.writeMethod = writeMethod;
56+
this.methodParameter = resolveMethodParameter();
57+
this.name = resolveName();
58+
this.annotations = resolveAnnotations();
59+
}
60+
61+
/**
62+
* The object declaring this property, either directly or in a superclass the object extends.
63+
*/
64+
public Class<?> getObjectType() {
65+
return objectType;
66+
}
67+
68+
/**
69+
* The name of the property e.g. 'foo'.
70+
*/
71+
public String getName() {
72+
return name;
73+
}
74+
75+
/**
76+
* The property type e.g. java.lang.String.
77+
*/
78+
public Class<?> getType() {
79+
return methodParameter.getParameterType();
80+
}
81+
82+
/**
83+
* The property getter method e.g. getFoo()
84+
*/
85+
public Method getReadMethod() {
86+
return readMethod;
87+
}
88+
89+
/**
90+
* The property setter method e.g. setFoo(String).
91+
*/
92+
public Method getWriteMethod() {
93+
return writeMethod;
94+
}
95+
96+
// package private
97+
98+
MethodParameter getMethodParameter() {
99+
return methodParameter;
100+
}
101+
102+
Annotation[] getAnnotations() {
103+
return annotations;
104+
}
105+
106+
// internal helpers
107+
108+
private String resolveName() {
109+
if (readMethod != null) {
110+
int index = readMethod.getName().indexOf("get");
111+
if (index != -1) {
112+
index += 3;
113+
} else {
114+
index = readMethod.getName().indexOf("is");
115+
if (index == -1) {
116+
throw new IllegalArgumentException("Not a getter method");
117+
}
118+
index += 2;
119+
}
120+
return StringUtils.uncapitalize(readMethod.getName().substring(index));
121+
} else {
122+
int index = writeMethod.getName().indexOf("set") + 3;
123+
if (index == -1) {
124+
throw new IllegalArgumentException("Not a setter method");
125+
}
126+
return StringUtils.uncapitalize(writeMethod.getName().substring(index));
127+
}
128+
}
129+
130+
private MethodParameter resolveMethodParameter() {
131+
MethodParameter read = resolveReadMethodParameter();
132+
MethodParameter write = resolveWriteMethodParameter();
133+
if (read == null && write == null) {
134+
throw new IllegalStateException("Property is neither readable or writeable");
135+
}
136+
if (read != null && write != null && !read.getParameterType().equals(write.getParameterType())) {
137+
throw new IllegalStateException("Read and write parameter types are not the same");
138+
}
139+
return read != null ? read : write;
140+
}
141+
142+
private MethodParameter resolveReadMethodParameter() {
143+
if (getReadMethod() == null) {
144+
return null;
145+
}
146+
return resolveParameterType(new MethodParameter(getReadMethod(), -1));
147+
}
148+
149+
private MethodParameter resolveWriteMethodParameter() {
150+
if (getWriteMethod() == null) {
151+
return null;
152+
}
153+
return resolveParameterType(new MethodParameter(getWriteMethod(), 0));
154+
}
155+
156+
private MethodParameter resolveParameterType(MethodParameter parameter) {
157+
// needed to resolve generic property types that parameterized by sub-classes e.g. T getFoo();
158+
GenericTypeResolver.resolveParameterType(parameter, getObjectType());
159+
return parameter;
160+
}
161+
162+
private Annotation[] resolveAnnotations() {
163+
Map<Class<?>, Annotation> annMap = new LinkedHashMap<Class<?>, Annotation>();
164+
Method readMethod = getReadMethod();
165+
if (readMethod != null) {
166+
for (Annotation ann : readMethod.getAnnotations()) {
167+
annMap.put(ann.annotationType(), ann);
168+
}
169+
}
170+
Method writeMethod = getWriteMethod();
171+
if (writeMethod != null) {
172+
for (Annotation ann : writeMethod.getAnnotations()) {
173+
annMap.put(ann.annotationType(), ann);
174+
}
175+
}
176+
Field field = getField();
177+
if (field != null) {
178+
for (Annotation ann : field.getAnnotations()) {
179+
annMap.put(ann.annotationType(), ann);
180+
}
181+
}
182+
return annMap.values().toArray(new Annotation[annMap.size()]);
183+
}
184+
185+
private Field getField() {
186+
String name = getName();
187+
if (!StringUtils.hasLength(name)) {
188+
return null;
189+
}
190+
Class<?> declaringClass = declaringClass();
191+
Field field = ReflectionUtils.findField(declaringClass, name);
192+
if (field == null) {
193+
// Same lenient fallback checking as in CachedIntrospectionResults...
194+
field = ReflectionUtils.findField(declaringClass,
195+
name.substring(0, 1).toLowerCase() + name.substring(1));
196+
if (field == null) {
197+
field = ReflectionUtils.findField(declaringClass,
198+
name.substring(0, 1).toUpperCase() + name.substring(1));
199+
}
200+
}
201+
return field;
202+
}
203+
204+
private Class<?> declaringClass() {
205+
if (getReadMethod() != null) {
206+
return getReadMethod().getDeclaringClass();
207+
} else {
208+
return getWriteMethod().getDeclaringClass();
209+
}
210+
}
211+
212+
}

0 commit comments

Comments
 (0)