001: /*
002: * Copyright 2005-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005: * in compliance with the License. You may obtain a copy of the License at
006: *
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software distributed under the License
010: * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011: * or implied. See the License for the specific language governing permissions and limitations under
012: * the License.
013: */
014:
015: package org.strecks.bind.internal;
016:
017: import java.lang.annotation.Annotation;
018: import java.lang.reflect.Method;
019: import java.util.LinkedHashMap;
020: import java.util.Map;
021:
022: import org.strecks.bind.factory.BindFactoryClass;
023: import org.strecks.bind.factory.BindHandlerFactory;
024: import org.strecks.bind.handler.BindHandler;
025: import org.strecks.converter.Converter;
026: import org.strecks.converter.handler.ConversionHandler;
027: import org.strecks.converter.handler.DefaultConversionHandler;
028: import org.strecks.converter.internal.ConverterReader;
029: import org.strecks.exceptions.ApplicationConfigurationException;
030: import org.strecks.util.ReflectHelper;
031:
032: /**
033: * Reads annotations on an action bean class and creates relevant <code>BindHandler</code> for
034: * bound properties
035: *
036: * @author Phil Zoio
037: */
038: public class BindAnnotationReader {
039:
040: public BindConvertInfo readBindables(Object this Bean) {
041:
042: Map<String, BindHandler> bindMap = new LinkedHashMap<String, BindHandler>();
043: Map<String, Converter> converterMap = new LinkedHashMap<String, Converter>();
044:
045: Class this Class = this Bean.getClass();
046: ConversionHandler conversionHandler = new DefaultConversionHandler();
047:
048: for (Method getterMethod : this Class.getMethods()) {
049:
050: Annotation[] annotations = getterMethod.getAnnotations();
051:
052: for (Annotation annotation : annotations) {
053:
054: Class<? extends Annotation> annotationType = annotation
055: .annotationType();
056: BindFactoryClass factoryClass = annotationType
057: .getAnnotation(BindFactoryClass.class);
058:
059: if (factoryClass != null) {
060:
061: checkMethodIsGetter(getterMethod, annotationType);
062:
063: String getterName = getterMethod.getName();
064: String this PropertyName = ReflectHelper
065: .getPropertyName(getterName);
066:
067: // check for an explicitly named converter
068: ConverterReader converterReader = new ConverterReader();
069: Converter explicitConverter = converterReader
070: .readConverter(getterMethod);
071:
072: // create factory
073: BindHandlerFactory factory = ReflectHelper
074: .createInstance(factoryClass.value(),
075: BindHandlerFactory.class);
076:
077: // use factory to create handler and register this
078: BindHandler handler = factory.createHandler(
079: annotation, getterMethod,
080: explicitConverter, conversionHandler);
081:
082: Class converterClass = null;
083: if (explicitConverter != null) {
084: converterClass = explicitConverter.getClass();
085: } else {
086: converterClass = handler.getConverter()
087: .getClass();
088: }
089:
090: checkActualConverter(this PropertyName,
091: getterMethod, converterClass);
092:
093: bindMap.put(this PropertyName, handler);
094: converterMap.put(this PropertyName, handler
095: .getConverter());
096:
097: }
098:
099: }
100:
101: }
102:
103: BindConvertInfo bci = new BindConvertInfo(bindMap,
104: converterMap, new DefaultConversionHandler());
105: return bci;
106:
107: }
108:
109: /**
110: * Checks that the type of the property matches the parameterized type of the converter
111: */
112: void checkActualConverter(String propertyName, Method getterMethod,
113: Class converterClass) {
114: Class genericType = ReflectHelper.getGenericType(
115: converterClass, Converter.class);
116:
117: Method setterMethod = ReflectHelper.getSetter(getterMethod);
118:
119: if (setterMethod == null) {
120: throw new ApplicationConfigurationException(
121: "Bind annotation used for "
122: + getterMethod
123: + " which has no corresponding setter method");
124: }
125:
126: if (genericType != null) {
127: Class<?> returnType = getterMethod.getReturnType();
128:
129: if (!returnType.equals(genericType))
130: throw new ApplicationConfigurationException(
131: "Method "
132: + getterMethod
133: + " is not type compatible with the type of the converter class "
134: + converterClass.getName()
135: + ", which is parameterized with the type "
136: + genericType.getName());
137:
138: Class<?> setterParameter = setterMethod.getParameterTypes()[0];
139: if (!setterParameter.equals(genericType))
140: throw new RuntimeException(
141: "Method "
142: + setterMethod
143: + " is not type compatible with the type of the converter class "
144: + converterClass.getName()
145: + ", which is parameterized with the type "
146: + genericType.getName());
147: }
148:
149: }
150:
151: private void checkMethodIsGetter(Method method,
152: Class<? extends Annotation> annotationType) {
153: if (!ReflectHelper.isGetter(method)) {
154: throw new ApplicationConfigurationException(
155: "Invalid @"
156: + annotationType.getSimpleName()
157: + " annotation for method "
158: + method
159: + ": annotation only supports getter methods of type String");
160: }
161: }
162:
163: }
|