001    /*
002     * Copyright 2002-2006 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    
017    package org.springframework.binding.support;
018    
019    import java.util.Map;
020    import java.util.LinkedHashMap;
021    import java.beans.PropertyDescriptor;
022    import java.lang.annotation.Annotation;
023    
024    import org.springframework.binding.value.ValueModel;
025    import org.springframework.richclient.util.AnnotationUtils;
026    import org.springframework.util.Assert;
027    
028    /**
029     * A JavaBean {@link org.springframework.binding.PropertyAccessStrategy
030     * PropertyAccessStrategy} that exposes JDK 1.5 Annotations for each property
031     * in the form of property level user metadata.  In order to remain backward
032     * compatible with 1.4 code, the annotations will be parsed by an installed
033     * {@link AnnotationTranslator} which typically stores the content of each
034     * annotation as key + value pairs in the user metadata.  If no translator is
035     * explicitly set, then this implementation will use
036     * {@link ReflectionAnnotationTranslator} by default.
037     * <p/>
038     * Note that this implementation will scan for annotations on both the getter
039     * and setter methods of the property.  If both getter and setter happen to
040     * define the same annotation, then the annotation on the getter will
041     * override the annotation on the setter.
042     *
043     * @author andy
044     * @since May 8, 2006 1:57:46 PM
045     */
046    public class AnnotationAwareBeanPropertyAccessStrategy extends BeanPropertyAccessStrategy {
047        private AnnotationTranslator annotationTranslator;
048    
049        public AnnotationAwareBeanPropertyAccessStrategy(Object bean) {
050            super(bean);
051        }
052    
053        public AnnotationAwareBeanPropertyAccessStrategy(final ValueModel domainObjectHolder) {
054            super(domainObjectHolder);
055        }
056    
057        protected AnnotationAwareBeanPropertyAccessStrategy(final BeanPropertyAccessStrategy parent, final String basePropertyPath) {
058            super(parent, basePropertyPath);
059        }
060    
061    
062    
063        //
064        // METHODS FROM BASE CLASS BeanPropertyAccessStrategy
065        //
066    
067    
068    
069        /**
070         * Retrieves annotations for the specified property as user metadata.
071         * Uses the intalled {@link #getAnnotationTranslator annotation translator}
072         * to "parse" annotations to their key + value pair components.
073         * <p/>
074         * Note that currently annotations are retranslated and the returned map
075         * is rebuilt on every invocation of this method.  No caching is attempted
076         * because the current use case of this method is a single call for each
077         * property during FormModel construction.  If this use case or usage
078         * pattern should be changed, then we may want to consider caching the
079         * result of this method.
080         *
081         * @param propertyPath
082         */
083        @Override
084        protected Map<String,Object> getAllUserMetadataFor(final String propertyPath) {
085            final PropertyDescriptor pd = getBeanWrapper().getPropertyDescriptor(propertyPath);
086            Assert.notNull(pd);
087            
088            final AnnotationTranslator translator = getAnnotationTranslator();
089            final Map<String,Object> ret = new LinkedHashMap<String,Object>();
090    
091            for(final Annotation annotation : AnnotationUtils.getAnnotationsFor(pd)) {
092                translator.translate(annotation, ret);
093            }
094            
095            return ret;
096        }
097    
098    
099    
100    
101    
102    
103    
104        //
105        // PROPERTY ACCESSORS
106        //
107    
108        public AnnotationTranslator getAnnotationTranslator() {
109            if(this.annotationTranslator == null) {
110                this.annotationTranslator = new ReflectionAnnotationTranslator();
111            }
112            return annotationTranslator;
113        }
114    
115        public void setAnnotationTranslator(final AnnotationTranslator annotationTranslator) {
116            this.annotationTranslator = annotationTranslator;
117        }
118    }