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 }