⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 beanwrapperimpl.java

📁 spring的源代码
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
			String nestedProperty = propertyPath.substring(0, pos);
			String nestedPath = propertyPath.substring(pos + 1);
			BeanWrapperImpl nestedBw = getNestedBeanWrapper(nestedProperty);
			return nestedBw.getBeanWrapperForPropertyPath(nestedPath);
		}
		else {
			return this;
		}
	}

	/**
	 * Recursively navigate to return a BeanWrapper for the nested property path.
	 * In case of an indexed or mapped property, all BeanWrappers that apply will
	 * be returned.
	 * @param propertyPath property property path, which may be nested
	 * @return a BeanWrapper for the target bean
	 */
	private List getBeanWrappersForPropertyPath(String propertyPath) {
		List beanWrappers = new ArrayList();
		int pos = propertyPath.indexOf(NESTED_PROPERTY_SEPARATOR);
		// handle nested properties recursively
		if (pos > -1) {
			String nestedProperty = propertyPath.substring(0, pos);
			String nestedPath = propertyPath.substring(pos + 1);
			if (nestedProperty.indexOf('[') == -1) {
				Class propertyType = getPropertyDescriptor(nestedProperty).getPropertyType();
				if (propertyType.isArray()) {
					Object[] array = (Object[]) getPropertyValue(nestedProperty);
					for (int i = 0; i < array.length; i++) {
						beanWrappers.addAll(
								getBeanWrappersForNestedProperty(propertyPath, nestedProperty + "[" + i + "]", nestedPath));
					}
					return beanWrappers;
				}
				else if (List.class.isAssignableFrom(propertyType)) {
					List list = (List) getPropertyValue(nestedProperty);
					for (int i = 0; i < list.size(); i++) {
						beanWrappers.addAll(
								getBeanWrappersForNestedProperty(propertyPath, nestedProperty + "[" + i + "]", nestedPath));
					}
					return beanWrappers;
				}
				else if (Map.class.isAssignableFrom(propertyType)) {
					Map map = (Map) getPropertyValue(nestedProperty);
					for (Iterator it = map.keySet().iterator(); it.hasNext();) {
						beanWrappers.addAll(
								getBeanWrappersForNestedProperty(propertyPath, nestedProperty + "[" + it.next() + "]", nestedPath));
					}
					return beanWrappers;
				}
			}
			beanWrappers.addAll(getBeanWrappersForNestedProperty(propertyPath, nestedProperty, nestedPath));
			return beanWrappers;
		}
		else {
			beanWrappers.add(this);
			return beanWrappers;
		}
	}

	private List getBeanWrappersForNestedProperty(String propertyPath, String nestedProperty, String nestedPath) {
		logger.debug("Navigating to nested property '" + nestedProperty + "' of property path '" + propertyPath + "'");
		BeanWrapperImpl nestedBw = getNestedBeanWrapper(nestedProperty);
		return nestedBw.getBeanWrappersForPropertyPath(nestedPath);
	}

	/**
	 * Retrieve a BeanWrapper for the given nested property.
	 * Create a new one if not found in the cache.
	 * <p>Note: Caching nested BeanWrappers is necessary now,
	 * to keep registered custom editors for nested properties.
	 * @param nestedProperty property to create the BeanWrapper for
	 * @return the BeanWrapper instance, either cached or newly created
	 */
	private BeanWrapperImpl getNestedBeanWrapper(String nestedProperty) {
		if (this.nestedBeanWrappers == null) {
			this.nestedBeanWrappers = new HashMap();
		}
		// get value of bean property
		String[] tokens = getPropertyNameTokens(nestedProperty);
		Object propertyValue = getPropertyValue(tokens[0], tokens[1], tokens[2]);
		String canonicalName = tokens[0];
		if (propertyValue == null) {
			throw new NullValueInNestedPathException(getWrappedClass(), canonicalName);
		}

		// lookup cached sub-BeanWrapper, create new one if not found
		BeanWrapperImpl nestedBw = (BeanWrapperImpl) this.nestedBeanWrappers.get(canonicalName);
		if (nestedBw == null) {
			logger.debug("Creating new nested BeanWrapper for property '" + canonicalName + "'");
			nestedBw = new BeanWrapperImpl(propertyValue, this.nestedPath + canonicalName + NESTED_PROPERTY_SEPARATOR);
			// inherit all type-specific PropertyEditors
			if (this.customEditors != null) {
				for (Iterator it = this.customEditors.keySet().iterator(); it.hasNext();) {
					Object key = it.next();
					if (key instanceof Class) {
						Class requiredType = (Class) key;
						PropertyEditor propertyEditor = (PropertyEditor) this.customEditors.get(key);
						nestedBw.registerCustomEditor(requiredType, null, propertyEditor);
					}
				}
			}
			this.nestedBeanWrappers.put(canonicalName, nestedBw);
		}
		else {
			logger.debug("Using cached nested BeanWrapper for property '" + canonicalName + "'");
		}
		return nestedBw;
	}

	private String[] getPropertyNameTokens(String propertyName) {
		String actualName = propertyName;
		String key = null;
		int keyStart = propertyName.indexOf('[');
		if (keyStart != -1 && propertyName.endsWith("]")) {
			actualName = propertyName.substring(0, keyStart);
			key = propertyName.substring(keyStart + 1, propertyName.length() - 1);
			if (key.startsWith("'") && key.endsWith("'")) {
				key = key.substring(1, key.length() - 1);
			}
			else if (key.startsWith("\"") && key.endsWith("\"")) {
				key = key.substring(1, key.length() - 1);
			}
		}
		String canonicalName = actualName;
		if (key != null) {
			canonicalName += "[" + key + "]";
		}
		return new String[] {canonicalName, actualName, key};
	}


	public Object getPropertyValue(String propertyName) throws BeansException {
		if (isNestedProperty(propertyName)) {
			BeanWrapper nestedBw = getBeanWrapperForPropertyPath(propertyName);
			return nestedBw.getPropertyValue(getFinalPath(propertyName));
		}
		String[] tokens = getPropertyNameTokens(propertyName);
		return getPropertyValue(tokens[0], tokens[1], tokens[2]);
	}

	private Object getPropertyValue(String propertyName, String actualName, String key) {
		PropertyDescriptor pd = getPropertyDescriptor(actualName);
		Method readMethod = pd.getReadMethod();
		if (readMethod == null) {
			throw new FatalBeanException("Cannot get property '" + actualName + "': not readable", null);
		}
		if (logger.isDebugEnabled())
			logger.debug("About to invoke read method [" + readMethod +
			             "] on object of class [" + this.object.getClass().getName() + "]");
		try {
			Object value = readMethod.invoke(this.object, null);
			if (key != null) {
				if (value == null) {
					throw new FatalBeanException("Cannot access indexed value in property referenced in indexed property path '" +
					                             propertyName + "': returned null");
				}
				else if (value.getClass().isArray()) {
					return Array.get(value, Integer.parseInt(key));
				}
				else if (value instanceof List) {
					List list = (List) value;
					return list.get(Integer.parseInt(key));
				}
				else if (value instanceof Set) {
					// apply index to Iterator in case of a Set
					Set set = (Set) value;
					int index = Integer.parseInt(key);
					Iterator it = set.iterator();
					for (int i = 0; it.hasNext(); i++) {
						Object elem = it.next();
						if (i == index) {
							return elem;
						}
					}
					throw new FatalBeanException("Cannot get element with index " + index + " from Set of size " +
																			 set.size() + ", accessed using property path '" + propertyName + "'");
				}
				else if (value instanceof Map) {
					Map map = (Map) value;
					return map.get(key);
				}
				else {
					throw new FatalBeanException("Property referenced in indexed property path '" + propertyName +
					                             "' is neither an array nor a List nor a Map; returned value was [" + value + "]");
				}
			}
			else {
				return value;
			}
		}
		catch (InvocationTargetException ex) {
			throw new FatalBeanException("Getter for property '" + actualName + "' threw exception", ex);
		}
		catch (IllegalAccessException ex) {
			throw new FatalBeanException("Illegal attempt to get property '" + actualName + "' threw exception", ex);
		}
		catch (IndexOutOfBoundsException ex) {
			throw new FatalBeanException("Index of out of bounds in property path '" + propertyName + "'", ex);
		}
		catch (NumberFormatException ex) {
			throw new FatalBeanException("Invalid index in property path '" + propertyName + "'");
		}
	}

	public void setPropertyValue(String propertyName, Object value) throws BeansException {
		if (isNestedProperty(propertyName)) {
			try {
				BeanWrapper nestedBw = getBeanWrapperForPropertyPath(propertyName);
				nestedBw.setPropertyValue(new PropertyValue(getFinalPath(propertyName), value));
				return;
			}
			catch (NullValueInNestedPathException ex) {
				// let this through
				throw ex;
			}
			catch (FatalBeanException ex) {
				// error in the nested path
				throw new NotWritablePropertyException(propertyName, getWrappedClass(), ex);
			}
		}
		String[] tokens = getPropertyNameTokens(propertyName);
		setPropertyValue(tokens[0], tokens[1], tokens[2], value);
	}

	private void setPropertyValue(String propertyName, String actualName, String key, Object value)
			throws BeansException {
		if (key != null) {
			Object propValue = getPropertyValue(actualName);
			if (propValue == null) {
				throw new FatalBeanException("Cannot access indexed value in property referenced in indexed property path '" +
																		 propertyName + "': returned null");
			}
			else if (propValue.getClass().isArray()) {
				Object newValue = doTypeConversionIfNecessary(propertyName, propertyName, null, value,
																											propValue.getClass().getComponentType());
				Array.set(propValue, Integer.parseInt(key), newValue);
			}
			else if (propValue instanceof List) {
				Object newValue = doTypeConversionIfNecessary(propertyName, propertyName, null, value, null);
				List list = (List) propValue;
				int index = Integer.parseInt(key);
				if (index < list.size()) {
					list.set(index, newValue);
				}
				else if (index >= list.size()) {
					for (int i = list.size(); i < index; i++) {
						try {
							list.add(null);
						}
						catch (NullPointerException ex) {
							throw new FatalBeanException("Cannot set element with index " + index + " in List of size " +
																					 list.size() + ", accessed using property path '" + propertyName +
																					 "': List does not support filling up gaps with null elements");
						}
					}
					list.add(newValue);
				}
			}
			else if (propValue instanceof Map) {
				Object newValue = doTypeConversionIfNecessary(propertyName, propertyName, null, value, null);
				Map map = (Map) propValue;
				map.put(key, newValue);
			}
			else {
				throw new FatalBeanException("Property referenced in indexed property path '" + propertyName +
																		 "' is neither an array nor a List nor a Map; returned value was [" + value + "]");
			}
		}
		else {
			if (!isWritableProperty(propertyName)) {
				throw new NotWritablePropertyException(propertyName, getWrappedClass());
			}
			PropertyDescriptor pd = getPropertyDescriptor(propertyName);
			Method writeMethod = pd.getWriteMethod();
			Object newValue = null;
			try {
				// old value may still be null
				newValue = doTypeConversionIfNecessary(propertyName, propertyName, null, value, pd.getPropertyType());

				if (pd.getPropertyType().isPrimitive() &&
						(newValue == null || "".equals(newValue))) {
					throw new IllegalArgumentException("Invalid value [" + value + "] for property '" +
								pd.getName() + "' of primitive type [" + pd.getPropertyType() + "]");
				}

				if (logger.isDebugEnabled()) {
					logger.debug("About to invoke write method [" + writeMethod +
											 "] on object of class [" + object.getClass().getName() + "]");
				}
				writeMethod.invoke(this.object, new Object[] { newValue });
				if (logger.isDebugEnabled()) {
					String msg = "Invoked write method [" + writeMethod + "] with value ";
					// only cause toString invocation of new value in case of simple property
					if (newValue == null || BeanUtils.isSimpleProperty(pd.getPropertyType())) {
						logger.debug(msg + "[" + newValue + "]");
					}
					else {
						logger.debug(msg + "of type [" + pd.getPropertyType().getName() + "]");
					}
				}
			}
			catch (InvocationTargetException ex) {
				// TODO could consider getting rid of PropertyChangeEvents as exception parameters
				// as they can never contain anything but null for the old value as we no longer
				// support event propagation.
				PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(this.object, this.nestedPath + propertyName,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -