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.binding.support;
017    
018    import org.springframework.beans.BeansException;
019    import org.springframework.beans.PropertyAccessor;
020    import org.springframework.binding.MutablePropertyAccessStrategy;
021    import org.springframework.binding.value.ValueModel;
022    import org.springframework.binding.value.support.ValueHolder;
023    import org.springframework.richclient.beans.DefaultMemberPropertyAccessor;
024    
025    /**
026     * An implementation of <code>MutablePropertyAccessStrategy</code> that
027     * provides type-save access to data specified by a class. The data is stored in
028     * a backing map.
029     *
030     * <p>
031     * As this class delegates to a <code>MapPropertyAccessor</code> for property
032     * access, there is full support for <b>nested properties</b> and collection
033     * types.
034     *
035     * @author Arne Limburg
036     * @see org.springframework.richclient.beans.DefaultMemberPropertyAccessor
037     */
038    public class ClassPropertyAccessStrategy extends AbstractPropertyAccessStrategy {
039    
040            private final DefaultMemberPropertyAccessor propertyAccessor;
041    
042            /**
043             * Creates a new instance of <tt>ClassPropertyAccessStrategy</tt>.
044             * @param targetClass the target class
045             */
046            public ClassPropertyAccessStrategy(Class targetClass) {
047                    super(new ValueHolder());
048                    propertyAccessor = new DefaultMemberPropertyAccessor(targetClass);
049            }
050    
051            /**
052             * Creates a new instance of <tt>ClassPropertyAccessStrategy</tt>.
053             * @param target the domain object
054             */
055            public ClassPropertyAccessStrategy(Object target) {
056                    this(new ValueHolder(target));
057            }
058    
059            /**
060             * Creates a new instance of <tt>ClassPropertyAccessStrategy</tt>.
061             * @param domainObjectHolder the value model containing the domain object
062             */
063            public ClassPropertyAccessStrategy(final ValueModel domainObjectHolder) {
064                    this(domainObjectHolder, false);
065            }
066    
067            /**
068             * Creates a new instance of <tt>ClassPropertyAccessStrategy</tt>.
069             * @param domainObjectHolder the value model containing the domain object
070             * @param fieldAccessEnabled whether the fields of the objects should be
071             * accessed directly where possible instead of using methods
072             */
073            public ClassPropertyAccessStrategy(final ValueModel domainObjectHolder, boolean fieldAccessEnabled) {
074                    this(domainObjectHolder, fieldAccessEnabled, true);
075            }
076    
077            /**
078             * Creates a new instance of <tt>ClassPropertyAccessStrategy</tt>.
079             * @param domainObjectHolder the value model containing the domain object
080             * @param fieldAccessEnabled whether the fields of the objects should be
081             * accessed directly where possible instead of using methods
082             * @param strictNullValueHandling whether a
083             * <tt>NullValueInNestedPathException</tt> should be thrown on nested
084             * null-values or <tt>null</tt> should be returned
085             */
086            public ClassPropertyAccessStrategy(final ValueModel domainObjectHolder, boolean fieldAccessEnabled,
087                            boolean strictNullValueHandling) {
088                    super(domainObjectHolder);
089                    propertyAccessor = new DefaultMemberPropertyAccessor(domainObjectHolder.getValue().getClass(),
090                                    domainObjectHolder.getValue(), fieldAccessEnabled, strictNullValueHandling);
091            }
092    
093            /**
094             * Creates a child instance of <tt>ClassPropertyAccessStrategy<tt>
095             * that will delegate to its parent for property access.
096             *
097             * @param parent <tt>ClassPropertyAccessStrategy</tt> which will be used to provide property access
098             * @param basePropertyPath property path that will as a base when accessing
099             *                         the parent <tt>ClassPropertyAccessStrategy</tt>
100             */
101            public ClassPropertyAccessStrategy(ClassPropertyAccessStrategy parent, String basePropertyPath) {
102                    super(parent, basePropertyPath);
103                    propertyAccessor = parent.propertyAccessor;
104            }
105    
106            protected PropertyAccessor getPropertyAccessor() {
107                    return propertyAccessor;
108            }
109    
110            public MutablePropertyAccessStrategy getPropertyAccessStrategyForPath(String propertyPath) throws BeansException {
111                    return new ClassPropertyAccessStrategy(this, getFullPropertyPath(propertyPath));
112            }
113    
114            public MutablePropertyAccessStrategy newPropertyAccessStrategy(ValueModel domainObjectHolder) {
115                    return new ClassPropertyAccessStrategy(domainObjectHolder);
116            }
117    
118            protected void domainObjectChanged() {
119                    propertyAccessor.setTarget(getDomainObject());
120            }
121    }