@Nullable protected Object convertForProperty( String propertyName, @Nullable Object oldValue, @Nullable Object newValue, TypeDescriptor td) throws TypeMismatchException { return convertIfNecessary(propertyName, oldValue, newValue, td.getType(), td); }
PropertyTokenHolder tokens = getPropertyNameTokens(nestedProperty); String canonicalName = tokens.canonicalName; Object value = getPropertyValue(tokens); if (value == null || (value instanceof Optional && !((Optional) value).isPresent())) { if (isAutoGrowNestedPaths()) { value = setDefaultValue(tokens); throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + canonicalName); if (nestedPa == null || nestedPa.getWrappedInstance() != ObjectUtils.unwrapOptional(value)) { if (logger.isTraceEnabled()) { logger.trace("Creating new nested " + getClass().getSimpleName() + " for property '" + canonicalName + "'"); nestedPa = newNestedPropertyAccessor(value, this.nestedPath + canonicalName + NESTED_PROPERTY_SEPARATOR); copyDefaultEditorsTo(nestedPa); copyCustomEditorsTo(nestedPa, canonicalName); this.nestedPropertyAccessors.put(canonicalName, nestedPa);
private Object setDefaultValue(PropertyTokenHolder tokens) { PropertyValue pv = createDefaultPropertyValue(tokens); setPropertyValue(tokens, pv); Object defaultValue = getPropertyValue(tokens); Assert.state(defaultValue != null, "Default value must not be null"); return defaultValue; }
/** * Create a new accessor for the given object, * registering a nested path that the object is in. * @param object object wrapped by this accessor * @param nestedPath the nested path of the object * @param parent the containing accessor (must not be {@code null}) */ protected AbstractNestablePropertyAccessor(Object object, String nestedPath, AbstractNestablePropertyAccessor parent) { setWrappedInstance(object, nestedPath, parent.getWrappedInstance()); setExtractOldValueForEditor(parent.isExtractOldValueForEditor()); setAutoGrowNestedPaths(parent.isAutoGrowNestedPaths()); setAutoGrowCollectionLimit(parent.getAutoGrowCollectionLimit()); setConversionService(parent.getConversionService()); }
@Override @Nullable public Object getPropertyValue(String propertyName) throws BeansException { AbstractNestablePropertyAccessor nestedPa = getPropertyAccessorForPropertyPath(propertyName); PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName)); return nestedPa.getPropertyValue(tokens); }
@SuppressWarnings("unchecked") private void processKeyedProperty(PropertyTokenHolder tokens, PropertyValue pv) { Object propValue = getPropertyHoldingValue(tokens); PropertyHandler ph = getLocalPropertyHandler(tokens.actualName); if (ph == null) { throw new InvalidPropertyException( getRootClass(), this.nestedPath + tokens.actualName, "No property handler found"); Object oldValue = null; try { if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) { oldValue = Array.get(propValue, arrayIndex); Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(), requiredType, ph.nested(tokens.keys.length)); int length = Array.getLength(propValue); Object newArray = Array.newInstance(componentType, arrayIndex + 1); System.arraycopy(propValue, 0, newArray, 0, length); setPropertyValue(tokens.actualName, newArray); propValue = getPropertyValue(tokens.actualName); throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName, "Invalid array index in property path '" + tokens.canonicalName + "'", ex); int index = Integer.parseInt(lastKey); Object oldValue = null; if (isExtractOldValueForEditor() && index < list.size()) { oldValue = list.get(index);
@Override public void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException { AbstractNestablePropertyAccessor nestedPa; try { nestedPa = getPropertyAccessorForPropertyPath(propertyName); } catch (NotReadablePropertyException ex) { throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName, "Nested property in path '" + propertyName + "' does not exist", ex); } PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName)); nestedPa.setPropertyValue(tokens, new PropertyValue(propertyName, value)); }
setExtractOldValueForEditor(parent.isExtractOldValueForEditor()); setAutoGrowNestedPaths(parent.isAutoGrowNestedPaths()); setAutoGrowCollectionLimit(parent.getAutoGrowCollectionLimit()); setConversionService(parent.getConversionService()); processKeyedProperty(tokens, pv); processLocalProperty(tokens, pv);
String propertyName = tokens.canonicalName; String actualName = tokens.actualName; PropertyHandler ph = getLocalPropertyHandler(actualName); if (ph == null || !ph.isReadable()) { throw new NotReadablePropertyException(getRootClass(), this.nestedPath + propertyName); if (tokens.keys != null) { if (value == null) { if (isAutoGrowNestedPaths()) { value = setDefaultValue(new PropertyTokenHolder(tokens.actualName)); throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName, "Cannot access indexed value of property referenced in indexed " + "property path '" + propertyName + "': returned null"); String key = tokens.keys[i]; if (value == null) { throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName, "Cannot access indexed value of property referenced in indexed " + "property path '" + propertyName + "': returned null"); value = growArrayIfNecessary(value, index, indexedPropertyName.toString()); value = Array.get(value, index); int index = Integer.parseInt(key); List<Object> list = (List<Object>) value; growCollectionIfNecessary(list, index, indexedPropertyName.toString(), ph, i + 1); value = list.get(index);
private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) { PropertyHandler ph = getLocalPropertyHandler(tokens.actualName); if (ph == null || !ph.isWritable()) { if (pv.isOptional()) { if (logger.isDebugEnabled()) { logger.debug("Ignoring optional value for property '" + tokens.actualName + "' - property not found on bean class [" + getRootClass().getName() + "]"); throw createNotWritablePropertyException(tokens.canonicalName); if (isExtractOldValueForEditor() && ph.isReadable()) { try { oldValue = ph.getValue(); valueToApply = convertForProperty( tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor()); getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue()); if (ex.getTargetException() instanceof ClassCastException) { throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException()); getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue()); throw new MethodInvocationException(pce, ex);
@Override @Nullable public TypeDescriptor getPropertyTypeDescriptor(String propertyName) throws BeansException { try { AbstractNestablePropertyAccessor nestedPa = getPropertyAccessorForPropertyPath(propertyName); String finalPath = getFinalPath(nestedPa, propertyName); PropertyTokenHolder tokens = getPropertyNameTokens(finalPath); PropertyHandler ph = nestedPa.getLocalPropertyHandler(tokens.actualName); if (ph != null) { if (tokens.keys != null) { if (ph.isReadable() || ph.isWritable()) { return ph.nested(tokens.keys.length); } } else { if (ph.isReadable() || ph.isWritable()) { return ph.toTypeDescriptor(); } } } } catch (InvalidPropertyException ex) { // Consider as not determinable. } return null; }
/** * Return the {@link PropertyHandler} for the specified {@code propertyName}, navigating * if necessary. Return {@code null} if not found rather than throwing an exception. * @param propertyName the property to obtain the descriptor for * @return the property descriptor for the specified property, * or {@code null} if not found * @throws BeansException in case of introspection failure */ @Nullable protected PropertyHandler getPropertyHandler(String propertyName) throws BeansException { Assert.notNull(propertyName, "Property name must not be null"); AbstractNestablePropertyAccessor nestedPa = getPropertyAccessorForPropertyPath(propertyName); return nestedPa.getLocalPropertyHandler(getFinalPath(nestedPa, propertyName)); }
logger.trace("Creating new nested " + getClass().getSimpleName() + " for property '" + canonicalName + "'"); nestedPa = newNestedPropertyAccessor(value, this.nestedPath + canonicalName + NESTED_PROPERTY_SEPARATOR); copyDefaultEditorsTo(nestedPa); copyCustomEditorsTo(nestedPa, canonicalName); this.nestedPropertyAccessors.put(canonicalName, nestedPa);
throw createNotWritablePropertyException(tokens.canonicalName); valueToApply = convertForProperty( tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());
private Object setDefaultValue(PropertyTokenHolder tokens) { PropertyValue pv = createDefaultPropertyValue(tokens); setPropertyValue(tokens, pv); return getPropertyValue(tokens); }
/** * Create a new accessor for the given object, * registering a nested path that the object is in. * @param object object wrapped by this accessor * @param nestedPath the nested path of the object * @param parent the containing accessor (must not be {@code null}) */ protected AbstractNestablePropertyAccessor(Object object, String nestedPath, AbstractNestablePropertyAccessor parent) { setWrappedInstance(object, nestedPath, parent.getWrappedInstance()); setExtractOldValueForEditor(parent.isExtractOldValueForEditor()); setAutoGrowNestedPaths(parent.isAutoGrowNestedPaths()); setAutoGrowCollectionLimit(parent.getAutoGrowCollectionLimit()); setConversionService(parent.getConversionService()); }
@SuppressWarnings("unchecked") private void processKeyedProperty(PropertyTokenHolder tokens, PropertyValue pv) { Object propValue = getPropertyHoldingValue(tokens); PropertyHandler ph = getLocalPropertyHandler(tokens.actualName); if (ph == null) { throw new InvalidPropertyException( getRootClass(), this.nestedPath + tokens.actualName, "No property handler found"); Object oldValue = null; try { if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) { oldValue = Array.get(propValue, arrayIndex); Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(), requiredType, ph.nested(tokens.keys.length)); int length = Array.getLength(propValue); Object newArray = Array.newInstance(componentType, arrayIndex + 1); System.arraycopy(propValue, 0, newArray, 0, length); setPropertyValue(tokens.actualName, newArray); propValue = getPropertyValue(tokens.actualName); throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName, "Invalid array index in property path '" + tokens.canonicalName + "'", ex); int index = Integer.parseInt(lastKey); Object oldValue = null; if (isExtractOldValueForEditor() && index < list.size()) { oldValue = list.get(index);
@Override public void setPropertyValue(PropertyValue pv) throws BeansException { PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens; if (tokens == null) { String propertyName = pv.getName(); AbstractNestablePropertyAccessor nestedPa; try { nestedPa = getPropertyAccessorForPropertyPath(propertyName); } catch (NotReadablePropertyException ex) { throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName, "Nested property in path '" + propertyName + "' does not exist", ex); } tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName)); if (nestedPa == this) { pv.getOriginalPropertyValue().resolvedTokens = tokens; } nestedPa.setPropertyValue(tokens, pv); } else { setPropertyValue(tokens, pv); } }
String propertyName = tokens.canonicalName; String actualName = tokens.actualName; PropertyHandler ph = getLocalPropertyHandler(actualName); if (ph == null || !ph.isReadable()) { throw new NotReadablePropertyException(getRootClass(), this.nestedPath + propertyName); if (tokens.keys != null) { if (value == null) { if (isAutoGrowNestedPaths()) { value = setDefaultValue(new PropertyTokenHolder(tokens.actualName)); throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName, "Cannot access indexed value of property referenced in indexed " + "property path '" + propertyName + "': returned null"); String key = tokens.keys[i]; if (value == null) { throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName, "Cannot access indexed value of property referenced in indexed " + "property path '" + propertyName + "': returned null"); value = growArrayIfNecessary(value, index, indexedPropertyName.toString()); value = Array.get(value, index); int index = Integer.parseInt(key); List<Object> list = (List<Object>) value; growCollectionIfNecessary(list, index, indexedPropertyName.toString(), ph, i + 1); value = list.get(index);
private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) { PropertyHandler ph = getLocalPropertyHandler(tokens.actualName); if (ph == null || !ph.isWritable()) { if (pv.isOptional()) { if (logger.isDebugEnabled()) { logger.debug("Ignoring optional value for property '" + tokens.actualName + "' - property not found on bean class [" + getRootClass().getName() + "]"); throw createNotWritablePropertyException(tokens.canonicalName); if (isExtractOldValueForEditor() && ph.isReadable()) { try { oldValue = ph.getValue(); valueToApply = convertForProperty( tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor()); getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue()); if (ex.getTargetException() instanceof ClassCastException) { throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException()); getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue()); throw new MethodInvocationException(pce, ex);