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