Skip to content

Commit d1c720c

Browse files
committed
GenericTypeAwarePropertyDescriptor implements equals/hashCode for proper lookups on IBM JVM 6
Issue: SPR-12185
1 parent 03e51d6 commit d1c720c

File tree

1 file changed

+174
-0
lines changed

1 file changed

+174
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/*
2+
* Copyright 2002-2014 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+
17+
package org.springframework.beans;
18+
19+
import java.beans.IntrospectionException;
20+
import java.beans.PropertyDescriptor;
21+
import java.lang.reflect.Method;
22+
import java.util.Enumeration;
23+
24+
import org.springframework.util.ObjectUtils;
25+
26+
/**
27+
* Common delegate methods for Spring's internal {@link PropertyDescriptor} implementations.
28+
*
29+
* @author Chris Beams
30+
* @author Juergen Hoeller
31+
*/
32+
class PropertyDescriptorUtils {
33+
34+
/**
35+
* See {@link java.beans.FeatureDescriptor}.
36+
*/
37+
public static void copyNonMethodProperties(PropertyDescriptor source, PropertyDescriptor target)
38+
throws IntrospectionException {
39+
40+
target.setExpert(source.isExpert());
41+
target.setHidden(source.isHidden());
42+
target.setPreferred(source.isPreferred());
43+
target.setName(source.getName());
44+
target.setShortDescription(source.getShortDescription());
45+
target.setDisplayName(source.getDisplayName());
46+
47+
// Copy all attributes (emulating behavior of private FeatureDescriptor#addTable)
48+
Enumeration<String> keys = source.attributeNames();
49+
while (keys.hasMoreElements()) {
50+
String key = keys.nextElement();
51+
target.setValue(key, source.getValue(key));
52+
}
53+
54+
// See java.beans.PropertyDescriptor#PropertyDescriptor(PropertyDescriptor)
55+
target.setPropertyEditorClass(source.getPropertyEditorClass());
56+
target.setBound(source.isBound());
57+
target.setConstrained(source.isConstrained());
58+
}
59+
60+
/**
61+
* See {@link java.beans.PropertyDescriptor#findPropertyType}.
62+
*/
63+
public static Class<?> findPropertyType(Method readMethod, Method writeMethod) throws IntrospectionException {
64+
Class<?> propertyType = null;
65+
66+
if (readMethod != null) {
67+
Class<?>[] params = readMethod.getParameterTypes();
68+
if (params.length != 0) {
69+
throw new IntrospectionException("Bad read method arg count: " + readMethod);
70+
}
71+
propertyType = readMethod.getReturnType();
72+
if (propertyType == Void.TYPE) {
73+
throw new IntrospectionException("Read method returns void: " + readMethod);
74+
}
75+
}
76+
77+
if (writeMethod != null) {
78+
Class<?> params[] = writeMethod.getParameterTypes();
79+
if (params.length != 1) {
80+
throw new IntrospectionException("Bad write method arg count: " + writeMethod);
81+
}
82+
if (propertyType != null) {
83+
if (propertyType.isAssignableFrom(params[0])) {
84+
// Write method's property type potentially more specific
85+
propertyType = params[0];
86+
}
87+
else if (params[0].isAssignableFrom(propertyType)) {
88+
// Proceed with read method's property type
89+
}
90+
else {
91+
throw new IntrospectionException(
92+
"Type mismatch between read and write methods: " + readMethod + " - " + writeMethod);
93+
}
94+
}
95+
else {
96+
propertyType = params[0];
97+
}
98+
}
99+
100+
return propertyType;
101+
}
102+
103+
/**
104+
* See {@link java.beans.IndexedPropertyDescriptor#findIndexedPropertyType}.
105+
*/
106+
public static Class<?> findIndexedPropertyType(String name, Class<?> propertyType,
107+
Method indexedReadMethod, Method indexedWriteMethod) throws IntrospectionException {
108+
109+
Class<?> indexedPropertyType = null;
110+
111+
if (indexedReadMethod != null) {
112+
Class<?> params[] = indexedReadMethod.getParameterTypes();
113+
if (params.length != 1) {
114+
throw new IntrospectionException("Bad indexed read method arg count: " + indexedReadMethod);
115+
}
116+
if (params[0] != Integer.TYPE) {
117+
throw new IntrospectionException("Non int index to indexed read method: " + indexedReadMethod);
118+
}
119+
indexedPropertyType = indexedReadMethod.getReturnType();
120+
if (indexedPropertyType == Void.TYPE) {
121+
throw new IntrospectionException("Indexed read method returns void: " + indexedReadMethod);
122+
}
123+
}
124+
125+
if (indexedWriteMethod != null) {
126+
Class<?> params[] = indexedWriteMethod.getParameterTypes();
127+
if (params.length != 2) {
128+
throw new IntrospectionException("Bad indexed write method arg count: " + indexedWriteMethod);
129+
}
130+
if (params[0] != Integer.TYPE) {
131+
throw new IntrospectionException("Non int index to indexed write method: " + indexedWriteMethod);
132+
}
133+
if (indexedPropertyType != null) {
134+
if (indexedPropertyType.isAssignableFrom(params[1])) {
135+
// Write method's property type potentially more specific
136+
indexedPropertyType = params[1];
137+
}
138+
else if (params[1].isAssignableFrom(indexedPropertyType)) {
139+
// Proceed with read method's property type
140+
}
141+
else {
142+
throw new IntrospectionException("Type mismatch between indexed read and write methods: " +
143+
indexedReadMethod + " - " + indexedWriteMethod);
144+
}
145+
}
146+
else {
147+
indexedPropertyType = params[1];
148+
}
149+
}
150+
151+
if (propertyType != null && (!propertyType.isArray() ||
152+
propertyType.getComponentType() != indexedPropertyType)) {
153+
throw new IntrospectionException("Type mismatch between indexed and non-indexed methods: " +
154+
indexedReadMethod + " - " + indexedWriteMethod);
155+
}
156+
157+
return indexedPropertyType;
158+
}
159+
160+
/**
161+
* Compare the given {@code PropertyDescriptors} and return {@code true} if
162+
* they are equivalent, i.e. their read method, write method, property type,
163+
* property editor and flags are equivalent.
164+
* @see java.beans.PropertyDescriptor#equals(Object)
165+
*/
166+
public static boolean equals(PropertyDescriptor pd, PropertyDescriptor otherPd) {
167+
return (ObjectUtils.nullSafeEquals(pd.getReadMethod(), otherPd.getReadMethod()) &&
168+
ObjectUtils.nullSafeEquals(pd.getWriteMethod(), otherPd.getWriteMethod()) &&
169+
ObjectUtils.nullSafeEquals(pd.getPropertyType(), otherPd.getPropertyType()) &&
170+
ObjectUtils.nullSafeEquals(pd.getPropertyEditorClass(), otherPd.getPropertyEditorClass()) &&
171+
pd.isBound() == otherPd.isBound() && pd.isConstrained() == otherPd.isConstrained());
172+
}
173+
174+
}

0 commit comments

Comments
 (0)