/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans;
import java.beans.
IntrospectionException;
import java.beans.
PropertyDescriptor;
import java.lang.reflect.
Method;
import java.util.
Enumeration;
import org.springframework.util.
ObjectUtils;
/**
* Common delegate methods for Spring's internal {@link PropertyDescriptor} implementations.
*
* @author Chris Beams
* @author Juergen Hoeller
*/
class
PropertyDescriptorUtils {
/**
* See {@link java.beans.FeatureDescriptor}.
*/
public static void
copyNonMethodProperties(
PropertyDescriptor source,
PropertyDescriptor target)
throws
IntrospectionException {
target.
setExpert(
source.
isExpert());
target.
setHidden(
source.
isHidden());
target.
setPreferred(
source.
isPreferred());
target.
setName(
source.
getName());
target.
setShortDescription(
source.
getShortDescription());
target.
setDisplayName(
source.
getDisplayName());
// Copy all attributes (emulating behavior of private FeatureDescriptor#addTable)
Enumeration<
String>
keys =
source.
attributeNames();
while (
keys.
hasMoreElements()) {
String key =
keys.
nextElement();
target.
setValue(
key,
source.
getValue(
key));
}
// See java.beans.PropertyDescriptor#PropertyDescriptor(PropertyDescriptor)
target.
setPropertyEditorClass(
source.
getPropertyEditorClass());
target.
setBound(
source.
isBound());
target.
setConstrained(
source.
isConstrained());
}
/**
* See {@link java.beans.PropertyDescriptor#findPropertyType}.
*/
public static
Class<?>
findPropertyType(
Method readMethod,
Method writeMethod) throws
IntrospectionException {
Class<?>
propertyType = null;
if (
readMethod != null) {
Class<?>[]
params =
readMethod.
getParameterTypes();
if (
params.length != 0) {
throw new
IntrospectionException("Bad read method arg count: " +
readMethod);
}
propertyType =
readMethod.
getReturnType();
if (
propertyType ==
Void.
TYPE) {
throw new
IntrospectionException("Read method returns void: " +
readMethod);
}
}
if (
writeMethod != null) {
Class<?>[]
params =
writeMethod.
getParameterTypes();
if (
params.length != 1) {
throw new
IntrospectionException("Bad write method arg count: " +
writeMethod);
}
if (
propertyType != null) {
if (
propertyType.
isAssignableFrom(
params[0])) {
// Write method's property type potentially more specific
propertyType =
params[0];
}
else if (
params[0].
isAssignableFrom(
propertyType)) {
// Proceed with read method's property type
}
else {
throw new
IntrospectionException(
"Type mismatch between read and write methods: " +
readMethod + " - " +
writeMethod);
}
}
else {
propertyType =
params[0];
}
}
return
propertyType;
}
/**
* See {@link java.beans.IndexedPropertyDescriptor#findIndexedPropertyType}.
*/
public static
Class<?>
findIndexedPropertyType(
String name,
Class<?>
propertyType,
Method indexedReadMethod,
Method indexedWriteMethod) throws
IntrospectionException {
Class<?>
indexedPropertyType = null;
if (
indexedReadMethod != null) {
Class<?>[]
params =
indexedReadMethod.
getParameterTypes();
if (
params.length != 1) {
throw new
IntrospectionException("Bad indexed read method arg count: " +
indexedReadMethod);
}
if (
params[0] !=
Integer.
TYPE) {
throw new
IntrospectionException("Non int index to indexed read method: " +
indexedReadMethod);
}
indexedPropertyType =
indexedReadMethod.
getReturnType();
if (
indexedPropertyType ==
Void.
TYPE) {
throw new
IntrospectionException("Indexed read method returns void: " +
indexedReadMethod);
}
}
if (
indexedWriteMethod != null) {
Class<?>[]
params =
indexedWriteMethod.
getParameterTypes();
if (
params.length != 2) {
throw new
IntrospectionException("Bad indexed write method arg count: " +
indexedWriteMethod);
}
if (
params[0] !=
Integer.
TYPE) {
throw new
IntrospectionException("Non int index to indexed write method: " +
indexedWriteMethod);
}
if (
indexedPropertyType != null) {
if (
indexedPropertyType.
isAssignableFrom(
params[1])) {
// Write method's property type potentially more specific
indexedPropertyType =
params[1];
}
else if (
params[1].
isAssignableFrom(
indexedPropertyType)) {
// Proceed with read method's property type
}
else {
throw new
IntrospectionException("Type mismatch between indexed read and write methods: " +
indexedReadMethod + " - " +
indexedWriteMethod);
}
}
else {
indexedPropertyType =
params[1];
}
}
if (
propertyType != null && (!
propertyType.
isArray() ||
propertyType.
getComponentType() !=
indexedPropertyType)) {
throw new
IntrospectionException("Type mismatch between indexed and non-indexed methods: " +
indexedReadMethod + " - " +
indexedWriteMethod);
}
return
indexedPropertyType;
}
/**
* Compare the given {@code PropertyDescriptors} and return {@code true} if
* they are equivalent, i.e. their read method, write method, property type,
* property editor and flags are equivalent.
* @see java.beans.PropertyDescriptor#equals(Object)
*/
public static boolean
equals(
PropertyDescriptor pd,
PropertyDescriptor otherPd) {
return (
ObjectUtils.
nullSafeEquals(
pd.
getReadMethod(),
otherPd.
getReadMethod()) &&
ObjectUtils.
nullSafeEquals(
pd.
getWriteMethod(),
otherPd.
getWriteMethod()) &&
ObjectUtils.
nullSafeEquals(
pd.
getPropertyType(),
otherPd.
getPropertyType()) &&
ObjectUtils.
nullSafeEquals(
pd.
getPropertyEditorClass(),
otherPd.
getPropertyEditorClass()) &&
pd.
isBound() ==
otherPd.
isBound() &&
pd.
isConstrained() ==
otherPd.
isConstrained());
}
}