View Javadoc

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