📄 beanwrapperimpl.java
字号:
* Bulk updates from PropertyValues are more powerful: this method is
* provided for convenience.
* @param map map containing properties to set, as name-value pairs.
* The map may include nested properties.
* @throws BeansException if there's a fatal, low-level exception
*/
public void setPropertyValues(Map map) throws BeansException {
setPropertyValues(new MutablePropertyValues(map));
}
public void setPropertyValues(PropertyValues pvs) throws BeansException {
setPropertyValues(pvs, false);
}
public void setPropertyValues(PropertyValues propertyValues, boolean ignoreUnknown) throws BeansException {
List propertyAccessExceptions = new ArrayList();
PropertyValue[] pvs = propertyValues.getPropertyValues();
for (int i = 0; i < pvs.length; i++) {
try {
// This method may throw any BeansException, which won't be caught
// here, if there is a critical failure such as no matching field.
// We can attempt to deal only with less serious exceptions.
setPropertyValue(pvs[i]);
}
catch (NotWritablePropertyException ex) {
if (!ignoreUnknown) {
throw ex;
}
// otherwise, just ignore it and continue...
}
catch (PropertyAccessException ex) {
propertyAccessExceptions.add(ex);
}
}
// If we encountered individual exceptions, throw the composite exception.
if (!propertyAccessExceptions.isEmpty()) {
Object[] paeArray = propertyAccessExceptions.toArray(
new PropertyAccessException[propertyAccessExceptions.size()]);
throw new PropertyAccessExceptionsException(this, (PropertyAccessException[]) paeArray);
}
}
private PropertyChangeEvent createPropertyChangeEvent(String propertyName, Object oldValue, Object newValue) {
return new PropertyChangeEvent(
(this.object != null ? this.object : "constructor"),
(propertyName != null ? this.nestedPath + propertyName : null),
oldValue, newValue);
}
/**
* Convert the value to the required type (if necessary from a String).
* Conversions from String to any type use the setAsText method of
* the PropertyEditor class. Note that a PropertyEditor must be registered
* for this class for this to work. This is a standard Java Beans API.
* A number of property editors are automatically registered by this class.
* @param newValue proposed change value.
* @param requiredType type we must convert to
* @throws BeansException if there is an internal error
* @return new value, possibly the result of type convertion
*/
public Object doTypeConversionIfNecessary(Object newValue, Class requiredType) throws BeansException {
return doTypeConversionIfNecessary(null, null, null, newValue, requiredType);
}
/**
* Convert the value to the required type (if necessary from a String),
* for the specified property.
* @param propertyName name of the property
* @param oldValue previous value, if available (may be null)
* @param newValue proposed change value.
* @param requiredType type we must convert to
* @throws BeansException if there is an internal error
* @return converted value (i.e. possibly the result of type conversion)
*/
protected Object doTypeConversionIfNecessary(String propertyName, String fullPropertyName,
Object oldValue, Object newValue,
Class requiredType) throws BeansException {
Object convertedValue = newValue;
if (convertedValue != null) {
// custom editor for this type?
PropertyEditor pe = findCustomEditor(requiredType, fullPropertyName);
// value not of required type?
if (pe != null ||
(requiredType != null &&
(requiredType.isArray() || !requiredType.isAssignableFrom(convertedValue.getClass())))) {
if (pe == null && requiredType != null) {
// no custom editor -> check BeanWrapperImpl's default editors
pe = (PropertyEditor) this.defaultEditors.get(requiredType);
if (pe == null) {
// no BeanWrapper default editor -> check standard JavaBean editors
pe = PropertyEditorManager.findEditor(requiredType);
}
}
if (requiredType != null && !requiredType.isArray() && convertedValue instanceof String[]) {
if (logger.isDebugEnabled()) {
logger.debug("Converting String array to comma-delimited String [" + convertedValue + "]");
}
convertedValue = StringUtils.arrayToCommaDelimitedString((String[]) convertedValue);
}
if (pe != null) {
if (convertedValue instanceof String) {
// use PropertyEditor's setAsText in case of a String value
if (logger.isDebugEnabled()) {
logger.debug("Converting String to [" + requiredType + "] using property editor [" + pe + "]");
}
try {
pe.setAsText((String) convertedValue);
convertedValue = pe.getValue();
}
catch (IllegalArgumentException ex) {
throw new TypeMismatchException(
createPropertyChangeEvent(fullPropertyName, oldValue, newValue), requiredType, ex);
}
}
else {
// Not a String -> use PropertyEditor's setValue.
// With standard PropertyEditors, this will return the very same object;
// we just want to allow special PropertyEditors to override setValue
// for type conversion from non-String values to the required type.
try {
pe.setValue(convertedValue);
convertedValue = pe.getValue();
}
catch (IllegalArgumentException ex) {
throw new TypeMismatchException(
createPropertyChangeEvent(fullPropertyName, oldValue, newValue), requiredType, ex);
}
}
}
// array required -> apply appropriate conversion of elements
if (requiredType != null && requiredType.isArray()) {
Class componentType = requiredType.getComponentType();
if (convertedValue instanceof Collection) {
// convert individual elements to array elements
Collection coll = (Collection) convertedValue;
Object result = Array.newInstance(componentType, coll.size());
int i = 0;
for (Iterator it = coll.iterator(); it.hasNext(); i++) {
Object value = doTypeConversionIfNecessary(
propertyName, propertyName + PROPERTY_KEY_PREFIX + i + PROPERTY_KEY_SUFFIX,
null, it.next(), componentType);
Array.set(result, i, value);
}
return result;
}
else if (convertedValue != null && convertedValue.getClass().isArray()) {
// convert individual elements to array elements
int arrayLength = Array.getLength(convertedValue);
Object result = Array.newInstance(componentType, arrayLength);
for (int i = 0; i < arrayLength; i++) {
Object value = doTypeConversionIfNecessary(
propertyName, propertyName + PROPERTY_KEY_PREFIX + i + PROPERTY_KEY_SUFFIX,
null, Array.get(convertedValue, i), componentType);
Array.set(result, i, value);
}
return result;
}
else {
// a plain value: convert it to an array with a single component
Object result = Array.newInstance(componentType, 1) ;
Object val = doTypeConversionIfNecessary(
propertyName, propertyName + PROPERTY_KEY_PREFIX + 0 + PROPERTY_KEY_SUFFIX,
null, convertedValue, componentType);
Array.set(result, 0, val);
return result;
}
}
}
// Throw explicit TypeMismatchException with full context information
// if the resulting value definitely doesn't match the required type.
if (convertedValue != null && requiredType != null && !requiredType.isPrimitive() &&
!requiredType.isAssignableFrom(convertedValue.getClass())) {
throw new TypeMismatchException(
createPropertyChangeEvent(fullPropertyName, oldValue, newValue), requiredType);
}
}
return convertedValue;
}
public PropertyDescriptor[] getPropertyDescriptors() {
return this.cachedIntrospectionResults.getBeanInfo().getPropertyDescriptors();
}
public PropertyDescriptor getPropertyDescriptor(String propertyName) throws BeansException {
if (propertyName == null) {
throw new IllegalArgumentException("Can't find property descriptor for null property");
}
PropertyDescriptor pd = getPropertyDescriptorInternal(propertyName);
if (pd != null) {
return pd;
}
else {
throw new InvalidPropertyException(getWrappedClass(), this.nestedPath + propertyName,
"No property '" + propertyName + "' found");
}
}
/**
* Internal version of getPropertyDescriptor:
* Returns null if not found rather than throwing an exception.
*/
protected PropertyDescriptor getPropertyDescriptorInternal(String propertyName) throws BeansException {
BeanWrapperImpl nestedBw = getBeanWrapperForPropertyPath(propertyName);
return nestedBw.cachedIntrospectionResults.getPropertyDescriptor(getFinalPath(nestedBw, propertyName));
}
public Class getPropertyType(String propertyName) throws BeansException {
try {
PropertyDescriptor pd = getPropertyDescriptorInternal(propertyName);
if (pd != null) {
return pd.getPropertyType();
}
else {
// maybe an indexed/mapped property
Object value = getPropertyValue(propertyName);
if (value != null) {
return value.getClass();
}
}
}
catch (InvalidPropertyException ex) {
// consider as not determinable
}
return null;
}
public boolean isReadableProperty(String propertyName) {
// This is a programming error, although asking for a property
// that doesn't exist is not.
if (propertyName == null) {
throw new IllegalArgumentException("Can't find readability status for null property");
}
try {
PropertyDescriptor pd = getPropertyDescriptorInternal(propertyName);
if (pd != null) {
if (pd.getReadMethod() != null) {
return true;
}
}
else {
// maybe an indexed/mapped property
getPropertyValue(propertyName);
return true;
}
}
catch (InvalidPropertyException ex) {
// cannot be evaluated, so can't be readable
}
return false;
}
public boolean isWritableProperty(String propertyName) {
// This is a programming error, although asking for a property
// that doesn't exist is not.
if (propertyName == null) {
throw new IllegalArgumentException("Can't find writability status for null property");
}
try {
PropertyDescriptor pd = getPropertyDescriptorInternal(propertyName);
if (pd != null) {
if (pd.getWriteMethod() != null) {
return true;
}
}
else {
// maybe an indexed/mapped property
getPropertyValue(propertyName);
return true;
}
}
catch (InvalidPropertyException ex) {
// cannot be evaluated, so can't be writable
}
return false;
}
//---------------------------------------------------------------------
// Diagnostics
//---------------------------------------------------------------------
/**
* This method is expensive! Only call for diagnostics and debugging reasons,
* not in production.
* @return a string describing the state of this object
*/
public String toString() {
StringBuffer sb = new StringBuffer();
try {
sb.append("BeanWrapperImpl: wrapping class [" + getWrappedClass().getName() + "]; ");
PropertyDescriptor pds[] = getPropertyDescriptors();
if (pds != null) {
for (int i = 0; i < pds.length; i++) {
Object val = getPropertyValue(pds[i].getName());
String valStr = (val != null) ? val.toString() : "null";
sb.append(pds[i].getName() + "={" + valStr + "}");
}
}
}
catch (Exception ex) {
sb.append("exception encountered: " + ex);
}
return sb.toString();
}
/**
* Holder for a registered custom editor with property name.
* Keeps the PropertyEditor itself plus the type it was registered for.
*/
private static class CustomEditorHolder {
private final PropertyEditor propertyEditor;
private final Class registeredType;
private CustomEditorHolder(PropertyEditor propertyEditor, Class registeredType) {
this.propertyEditor = propertyEditor;
this.registeredType = registeredType;
}
private PropertyEditor getPropertyEditor() {
return propertyEditor;
}
private Class getRegisteredType() {
return registeredType;
}
private PropertyEditor getPropertyEditor(Class requiredType) {
// Special case: If no required type specified, which usually only happens for
// Collection elements, or required type is not assignable to registered type,
// which usually only happens for generic properties of type Object -
// then return PropertyEditor if not registered for Collection or array type.
// (If not registered for Collection or array, it is assumed to be intended
// for elements.)
if (this.registeredType == null ||
(requiredType != null &&
(BeanUtils.isAssignable(this.registeredType, requiredType) ||
BeanUtils.isAssignable(requiredType, this.registeredType))) ||
(requiredType == null &&
(!Collection.class.isAssignableFrom(this.registeredType) && !this.registeredType.isArray()))) {
return this.propertyEditor;
}
else {
return null;
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -