001 /* 002 * Copyright 2007 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 005 * use this file except in compliance with the License. You may obtain a copy of 006 * the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 013 * License for the specific language governing permissions and limitations under 014 * the License. 015 */ 016 package org.springframework.richclient.beans; 017 018 import org.springframework.beans.NullValueInNestedPathException; 019 import org.springframework.beans.PropertyAccessor; 020 import org.springframework.util.CachingMapDecorator; 021 022 /** 023 * This implementation extends {@link AbstractMemberPropertyAccessor} with the 024 * functionality of nested property handling. 025 * 026 * @author Arne Limburg 027 * 028 */ 029 public abstract class AbstractNestedMemberPropertyAccessor extends AbstractMemberPropertyAccessor { 030 031 private AbstractNestedMemberPropertyAccessor parentPropertyAccessor; 032 033 private String basePropertyName; 034 035 private final ChildPropertyAccessorCache childPropertyAccessors = new ChildPropertyAccessorCache(); 036 037 private final boolean strictNullHandlingEnabled; 038 039 protected AbstractNestedMemberPropertyAccessor(Class targetClass, boolean fieldAccessEnabled, 040 boolean strictNullHandlingEnabled) { 041 super(targetClass, fieldAccessEnabled); 042 this.strictNullHandlingEnabled = strictNullHandlingEnabled; 043 } 044 045 public AbstractNestedMemberPropertyAccessor(AbstractNestedMemberPropertyAccessor parent, String baseProperty) { 046 super(parent.getPropertyType(baseProperty), parent.isFieldAccessEnabled()); 047 parentPropertyAccessor = parent; 048 basePropertyName = baseProperty; 049 strictNullHandlingEnabled = parent.strictNullHandlingEnabled; 050 } 051 052 public boolean isStrictNullHandlingEnabled() { 053 return strictNullHandlingEnabled; 054 } 055 056 protected AbstractNestedMemberPropertyAccessor getParentPropertyAccessor() { 057 return parentPropertyAccessor; 058 } 059 060 protected String getBasePropertyName() { 061 return basePropertyName; 062 } 063 064 public Object getTarget() { 065 if (parentPropertyAccessor != null && basePropertyName != null) { 066 return parentPropertyAccessor.getPropertyValue(basePropertyName); 067 } 068 else { 069 return null; 070 } 071 } 072 073 public Class getTargetClass() { 074 if (parentPropertyAccessor != null) { 075 return parentPropertyAccessor.getPropertyType(basePropertyName); 076 } 077 else { 078 return super.getTargetClass(); 079 } 080 } 081 082 public boolean isReadableProperty(String propertyPath) { 083 if (PropertyAccessorUtils.isNestedProperty(propertyPath)) { 084 String baseProperty = getBasePropertyName(propertyPath); 085 String childPropertyPath = getChildPropertyPath(propertyPath); 086 if (!super.isReadableProperty(baseProperty)) { 087 return false; 088 } 089 else { 090 return ((PropertyAccessor) childPropertyAccessors.get(baseProperty)) 091 .isReadableProperty(childPropertyPath); 092 } 093 } 094 else { 095 return super.isReadableProperty(propertyPath); 096 } 097 } 098 099 public boolean isWritableProperty(String propertyPath) { 100 if (PropertyAccessorUtils.isNestedProperty(propertyPath)) { 101 String baseProperty = getBasePropertyName(propertyPath); 102 String childPropertyPath = getChildPropertyPath(propertyPath); 103 return super.isReadableProperty(baseProperty) 104 && ((PropertyAccessor) childPropertyAccessors.get(baseProperty)) 105 .isWritableProperty(childPropertyPath); 106 } 107 else { 108 return super.isWritableProperty(propertyPath); 109 } 110 } 111 112 public Class getPropertyType(String propertyPath) { 113 if (PropertyAccessorUtils.isNestedProperty(propertyPath)) { 114 String baseProperty = getBasePropertyName(propertyPath); 115 String childPropertyPath = getChildPropertyPath(propertyPath); 116 return ((PropertyAccessor) childPropertyAccessors.get(baseProperty)).getPropertyType(childPropertyPath); 117 } 118 else { 119 return super.getPropertyType(propertyPath); 120 } 121 } 122 123 public Object getPropertyValue(String propertyPath) { 124 if (PropertyAccessorUtils.isNestedProperty(propertyPath)) { 125 String baseProperty = getBasePropertyName(propertyPath); 126 String childPropertyPath = getChildPropertyPath(propertyPath); 127 return ((PropertyAccessor) childPropertyAccessors.get(baseProperty)).getPropertyValue(childPropertyPath); 128 } 129 else if (isStrictNullHandlingEnabled() && getTarget() == null) { 130 throw new NullValueInNestedPathException(getTargetClass(), propertyPath); 131 } 132 else { 133 return super.getPropertyValue(propertyPath); 134 } 135 } 136 137 public void setPropertyValue(String propertyPath, Object value) { 138 if (PropertyAccessorUtils.isNestedProperty(propertyPath)) { 139 String baseProperty = getBasePropertyName(propertyPath); 140 String childPropertyPath = getChildPropertyPath(propertyPath); 141 ((PropertyAccessor) childPropertyAccessors.get(baseProperty)).setPropertyValue(childPropertyPath, value); 142 } 143 else if (isStrictNullHandlingEnabled() && getTarget() == null) { 144 throw new NullValueInNestedPathException(getTargetClass(), propertyPath); 145 } 146 else { 147 super.setPropertyValue(propertyPath, value); 148 } 149 } 150 151 protected String getBasePropertyName(String propertyPath) { 152 int index = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath); 153 return index == -1 ? propertyPath : propertyPath.substring(0, index); 154 } 155 156 protected String getChildPropertyPath(String propertyPath) { 157 int index = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath); 158 if (index == -1) { 159 return ""; 160 } 161 return propertyPath.substring(index + 1); 162 } 163 164 protected PropertyAccessor getChildPropertyAccessor(String propertyName) { 165 return (PropertyAccessor) childPropertyAccessors.get(propertyName); 166 } 167 168 protected abstract AbstractNestedMemberPropertyAccessor createChildPropertyAccessor(String propertyName); 169 170 protected void clearChildPropertyAccessorCache() { 171 childPropertyAccessors.clear(); 172 } 173 174 private class ChildPropertyAccessorCache extends CachingMapDecorator { 175 176 protected Object create(Object propertyName) { 177 return createChildPropertyAccessor((String) propertyName); 178 } 179 } 180 }