View Javadoc

1   /*
2    * Copyright 2004-2009 the Seasar Foundation and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.seasar.cubby.internal.controller.impl;
17  
18  import java.lang.reflect.Array;
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.LinkedHashSet;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.Set;
25  
26  import org.seasar.cubby.action.ActionContext;
27  import org.seasar.cubby.action.FieldInfo;
28  import org.seasar.cubby.action.MessageInfo;
29  import org.seasar.cubby.action.RequestParameter;
30  import org.seasar.cubby.converter.ConversionException;
31  import org.seasar.cubby.converter.ConversionHelper;
32  import org.seasar.cubby.converter.Converter;
33  import org.seasar.cubby.converter.impl.ConversionHelperImpl;
34  import org.seasar.cubby.internal.controller.ConversionFailure;
35  import org.seasar.cubby.internal.controller.RequestParameterBinder;
36  import org.seasar.cubby.internal.util.StringUtils;
37  import org.seasar.cubby.spi.ConverterProvider;
38  import org.seasar.cubby.spi.ProviderFactory;
39  import org.seasar.cubby.spi.beans.Attribute;
40  import org.seasar.cubby.spi.beans.BeanDesc;
41  import org.seasar.cubby.spi.beans.BeanDescFactory;
42  import org.seasar.cubby.spi.beans.ParameterizedClassDesc;
43  
44  /**
45   * 要求パラメータをオブジェクトへバインドするクラスの実装です。
46   * 
47   * @author baba
48   */
49  public class RequestParameterBinderImpl implements RequestParameterBinder {
50  
51  	/** 変換のヘルパクラス。 */
52  	private final ConversionHelper conversionHelper = new ConversionHelperImpl();
53  
54  	/**
55  	 * {@inheritDoc}
56  	 */
57  	public List<ConversionFailure> bind(
58  			final Map<String, Object[]> parameterMap, final Object dest,
59  			final ActionContext actionContext) {
60  		final List<ConversionFailure> conversionFailures = new ArrayList<ConversionFailure>();
61  		if (parameterMap == null || parameterMap.isEmpty()) {
62  			return conversionFailures;
63  		}
64  
65  		final ConverterProvider converterProvider = ProviderFactory
66  				.get(ConverterProvider.class);
67  		final BeanDesc beanDesc = BeanDescFactory.getBeanDesc(dest.getClass());
68  		final Collection<Attribute> attributes;
69  		if (actionContext.isBindRequestParameterToAllProperties()) {
70  			attributes = new ArrayList<Attribute>();
71  			attributes.addAll(beanDesc.findtPropertyAttributes());
72  			attributes.addAll(beanDesc
73  					.findAttributesAnnotatedWith(RequestParameter.class));
74  		} else {
75  			attributes = beanDesc
76  					.findAttributesAnnotatedWith(RequestParameter.class);
77  		}
78  
79  		for (final Attribute attribute : attributes) {
80  			final RequestParameter requestParameter = attribute
81  					.getAnnotation(RequestParameter.class);
82  
83  			final String parameterName;
84  			if (requestParameter != null
85  					&& !StringUtils.isEmpty(requestParameter.name())) {
86  				parameterName = requestParameter.name();
87  			} else {
88  				parameterName = attribute.getName();
89  			}
90  
91  			if (!parameterMap.containsKey(parameterName)) {
92  				continue;
93  			}
94  
95  			final Object[] parameterValue = parameterMap.get(parameterName);
96  
97  			final Class<? extends Converter> converterType;
98  			if (requestParameter != null) {
99  				converterType = requestParameter.converter();
100 			} else {
101 				converterType = null;
102 			}
103 
104 			final Object value = convert(converterProvider, parameterValue,
105 					attribute.getType(), attribute.getParameterizedClassDesc(),
106 					converterType, parameterName, conversionFailures);
107 
108 			attribute.setValue(dest, value);
109 		}
110 
111 		return conversionFailures;
112 	}
113 
114 	/**
115 	 * 指定された要求パラメータの値を出力先のプロパティの型に変換します。
116 	 * 
117 	 * @param converterProvider
118 	 *            コンバータプロバイダ
119 	 * @param values
120 	 *            要求パラメータの値
121 	 * @param type
122 	 *            変換する型
123 	 * @param parameterizedClassDesc
124 	 *            パラメタ化された型の情報
125 	 * @param converterType
126 	 *            コンバータの型
127 	 * @param parameterName
128 	 *            パラメータ名
129 	 * @param 型変換失敗のリスト
130 	 * @return 変換された値
131 	 */
132 	private Object convert(final ConverterProvider converterProvider,
133 			final Object[] values, final Class<?> destClass,
134 			final ParameterizedClassDesc parameterizedClassDesc,
135 			final Class<? extends Converter> converterType,
136 			final String parameterName,
137 			final List<ConversionFailure> conversionFailures) {
138 
139 		final Converter converter;
140 		if (converterType != null && !converterType.equals(Converter.class)) {
141 			converter = converterProvider.getConverter(converterType);
142 		} else {
143 			final Class<?> componentType = values.getClass().getComponentType();
144 			converter = converterProvider
145 					.getConverter(componentType, destClass);
146 		}
147 		if (converter != null) {
148 			try {
149 				return converter.convertToObject(values[0], destClass,
150 						conversionHelper);
151 			} catch (final ConversionException e) {
152 				final FieldInfo fieldInfo = new FieldInfo(parameterName);
153 				final MessageInfo messageInfo = e.getMessageInfo();
154 				final ConversionFailure conversionFaiure = new ConversionFailure(
155 						parameterName, messageInfo, fieldInfo);
156 				conversionFailures.add(conversionFaiure);
157 				return null;
158 			}
159 		}
160 
161 		if (destClass.isArray()) {
162 			return convertToArray(converterProvider, values, destClass
163 					.getComponentType(), parameterName, conversionFailures);
164 		}
165 		if (List.class.isAssignableFrom(destClass)) {
166 			final List<Object> list = new ArrayList<Object>();
167 			convertToCollection(converterProvider, values, list, destClass,
168 					parameterizedClassDesc, parameterName, conversionFailures);
169 			return list;
170 		}
171 		if (Set.class.isAssignableFrom(destClass)) {
172 			final Set<Object> set = new LinkedHashSet<Object>();
173 			convertToCollection(converterProvider, values, set, destClass,
174 					parameterizedClassDesc, parameterName, conversionFailures);
175 			return set;
176 		}
177 
178 		try {
179 			return convertToScalar(converterProvider, values[0], destClass);
180 		} catch (final ConversionException e) {
181 			final FieldInfo fieldInfo = new FieldInfo(parameterName);
182 			final MessageInfo messageInfo = e.getMessageInfo();
183 			final ConversionFailure conversionFaiure = new ConversionFailure(
184 					parameterName, messageInfo, fieldInfo);
185 			conversionFailures.add(conversionFaiure);
186 			return null;
187 		}
188 	}
189 
190 	/**
191 	 * 指定された値を指定された要素の型の配列に変換します。
192 	 * 
193 	 * @param converterFactory
194 	 *            コンバータプロバイダ
195 	 * @param values
196 	 *            変換する値
197 	 * @param componentType
198 	 *            要素の型
199 	 * @param parameterName
200 	 *            パラメータ名
201 	 * @param conversionFailures
202 	 *            型変換失敗のリスト
203 	 * @return 変換後の値
204 	 */
205 	private Object convertToArray(final ConverterProvider converterProvider,
206 			final Object[] values, final Class<?> componentType,
207 			final String parameterName,
208 			final List<ConversionFailure> conversionFailures) {
209 		final Object dest = Array.newInstance(componentType, values.length);
210 		for (int i = 0; i < values.length; i++) {
211 			try {
212 				final Object convertedValue = convertToScalar(
213 						converterProvider, values[i], componentType);
214 				Array.set(dest, i, convertedValue);
215 			} catch (final ConversionException e) {
216 				final FieldInfo fieldInfo = new FieldInfo(parameterName, i);
217 				final MessageInfo messageInfo = e.getMessageInfo();
218 				final ConversionFailure conversionFaiure = new ConversionFailure(
219 						parameterName, messageInfo, fieldInfo);
220 				conversionFailures.add(conversionFaiure);
221 			}
222 		}
223 		return dest;
224 	}
225 
226 	/**
227 	 * 指定された値を変換してコレクションに追加します。
228 	 * 
229 	 * @param converterProvider
230 	 *            コンバータプロバイダ
231 	 * @param values
232 	 *            変換する値
233 	 * @param collection
234 	 *            コレクション
235 	 * @param type
236 	 *            変換する型
237 	 * @param parameterizedClassDesc
238 	 *            パラメタ化された型の情報
239 	 * @param parameterName
240 	 *            パラメータ名
241 	 * @param conversionFailures
242 	 *            型変換失敗のリスト
243 	 */
244 	private void convertToCollection(final ConverterProvider converterProvider,
245 			final Object[] values, final Collection<Object> collection,
246 			final Class<?> type,
247 			final ParameterizedClassDesc parameterizedClassDesc,
248 			final String parameterName,
249 			final List<ConversionFailure> conversionFailures) {
250 		if (parameterizedClassDesc != null
251 				&& parameterizedClassDesc.isParameterizedClass()) {
252 			final Class<?> destElementType = parameterizedClassDesc
253 					.getArguments()[0].getRawClass();
254 			for (int i = 0; i < values.length; i++) {
255 				final Object value = values[i];
256 				try {
257 					final Object convertedValue = convertToScalar(
258 							converterProvider, value, destElementType);
259 					collection.add(convertedValue);
260 				} catch (final ConversionException e) {
261 					collection.add(null);
262 					final FieldInfo fieldInfo = new FieldInfo(parameterName, i);
263 					final MessageInfo messageInfo = e.getMessageInfo();
264 					final ConversionFailure conversionFaiure = new ConversionFailure(
265 							parameterName, messageInfo, fieldInfo);
266 					conversionFailures.add(conversionFaiure);
267 				}
268 			}
269 		} else {
270 			for (final Object value : values) {
271 				collection.add(value);
272 			}
273 		}
274 	}
275 
276 	/**
277 	 * 指定された値を指定された型に変換します。
278 	 * 
279 	 * @param converterProvider
280 	 *            コンバータプロバイダ
281 	 * @param value
282 	 *            変換する値
283 	 * @param destClass
284 	 *            変換する型
285 	 * @return 変換後の値
286 	 * @throws ConversionException
287 	 *             型変換に失敗した場合
288 	 */
289 	private Object convertToScalar(final ConverterProvider converterProvider,
290 			final Object value, final Class<?> destClass)
291 			throws ConversionException {
292 		if (value == null) {
293 			return null;
294 		}
295 		if (destClass.isAssignableFrom(value.getClass())) {
296 			return value;
297 		}
298 		final Converter converter = converterProvider.getConverter(value
299 				.getClass(), destClass);
300 		if (converter == null) {
301 			return null;
302 		}
303 		return converter.convertToObject(value, destClass, conversionHelper);
304 	}
305 
306 }