##### Coverage Report - org.seasar.cubby.internal.controller.impl.RequestParameterBinderImpl

Classes in this File | Line Coverage | Branch Coverage | Complexity
RequestParameterBinderImpl |
82% | 76/92
84% | 37/44
| 8.2;8.2

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 | 10 |
     public class RequestParameterBinderImpl implements RequestParameterBinder {
50 |  |
51 |  |
             /** 変換のヘルパクラス。 */
52 | 10 |
             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 | 10 |
                     final List<ConversionFailure> conversionFailures = new ArrayList<ConversionFailure>();
61 | 10 |
                     if (parameterMap == null || parameterMap.isEmpty()) {
62 | 1 |
                             return conversionFailures;
63 |  |
                     }
64 |  |
65 | 9 |
                     final ConverterProvider converterProvider = ProviderFactory
66 |  |
                                     .get(ConverterProvider.class);
67 | 9 |
                     final BeanDesc beanDesc = BeanDescFactory.getBeanDesc(dest.getClass());
68 |  |
                     final Collection<Attribute> attributes;
69 | 9 |
                     if (actionContext.isBindRequestParameterToAllProperties()) {
70 | 9 |
                             attributes = new ArrayList<Attribute>();
71 | 9 |
                             attributes.addAll(beanDesc.findtPropertyAttributes());
72 | 9 |
                             attributes.addAll(beanDesc
73 |  |
                                             .findAttributesAnnotatedWith(RequestParameter.class));
74 |  |
                     } else {
75 | 0 |
                             attributes = beanDesc
76 |  |
                                             .findAttributesAnnotatedWith(RequestParameter.class);
77 |  |
                     }
78 |  |
79 | 9 |
                     for (final Attribute attribute : attributes) {
80 | 134 |
                             final RequestParameter requestParameter = attribute
81 |  |
                                             .getAnnotation(RequestParameter.class);
82 |  |
83 |  |
                             final String parameterName;
84 | 134 |
                             if (requestParameter != null
85 |  |
                                             && !StringUtils.isEmpty(requestParameter.name())) {
86 | 4 |
                                     parameterName = requestParameter.name();
87 |  |
                             } else {
88 | 130 |
                                     parameterName = attribute.getName();
89 |  |
                             }
90 |  |
91 | 134 |
                             if (!parameterMap.containsKey(parameterName)) {
92 | 29 |
                                     continue;
93 |  |
                             }
94 |  |
95 | 105 |
                             final Object[] parameterValue = parameterMap.get(parameterName);
96 |  |
97 |  |
                             final Class<? extends Converter> converterType;
98 | 105 |
                             if (requestParameter != null) {
99 | 8 |
                                     converterType = requestParameter.converter();
100 |  |
                             } else {
101 | 97 |
                                     converterType = null;
102 |  |
                             }
103 |  |
104 | 105 |
                             final Object value = convert(converterProvider, parameterValue,
105 |  |
                                             attribute.getType(), attribute.getParameterizedClassDesc(),
106 |  |
                                             converterType, parameterName, conversionFailures);
107 |  |
108 | 105 |
                             attribute.setValue(dest, value);
109 | 105 |
                     }
110 |  |
111 | 9 |
                     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 | 105 |
                     if (converterType != null && !converterType.equals(Converter.class)) {
141 | 4 |
                             converter = converterProvider.getConverter(converterType);
142 |  |
                     } else {
143 | 101 |
                             final Class<?> componentType = values.getClass().getComponentType();
144 | 101 |
                             converter = converterProvider
145 |  |
                                             .getConverter(componentType, destClass);
146 |  |
                     }
147 | 105 |
                     if (converter != null) {
148 |  |
                             try {
149 | 50 |
                                     return converter.convertToObject(values[0], destClass,
150 |  |
                                                     conversionHelper);
151 | 19 |
                             } catch (final ConversionException e) {
152 | 19 |
                                     final FieldInfo fieldInfo = new FieldInfo(parameterName);
153 | 19 |
                                     final MessageInfo messageInfo = e.getMessageInfo();
154 | 19 |
                                     final ConversionFailure conversionFaiure = new ConversionFailure(
155 |  |
                                                     parameterName, messageInfo, fieldInfo);
156 | 19 |
                                     conversionFailures.add(conversionFaiure);
157 | 19 |
                                     return null;
158 |  |
                             }
159 |  |
                     }
160 |  |
161 | 55 |
                     if (destClass.isArray()) {
162 | 46 |
                             return convertToArray(converterProvider, values, destClass
163 |  |
                                             .getComponentType(), parameterName, conversionFailures);
164 |  |
                     }
165 | 9 |
                     if (List.class.isAssignableFrom(destClass)) {
166 | 3 |
                             final List<Object> list = new ArrayList<Object>();
167 | 3 |
                             convertToCollection(converterProvider, values, list, destClass,
168 |  |
                                             parameterizedClassDesc, parameterName, conversionFailures);
169 | 3 |
                             return list;
170 |  |
                     }
171 | 6 |
                     if (Set.class.isAssignableFrom(destClass)) {
172 | 1 |
                             final Set<Object> set = new LinkedHashSet<Object>();
173 | 1 |
                             convertToCollection(converterProvider, values, set, destClass,
174 |  |
                                             parameterizedClassDesc, parameterName, conversionFailures);
175 | 1 |
                             return set;
176 |  |
                     }
177 |  |
178 |  |
                     try {
179 | 5 |
                             return convertToScalar(converterProvider, values[0], destClass);
180 | 0 |
                     } catch (final ConversionException e) {
181 | 0 |
                             final FieldInfo fieldInfo = new FieldInfo(parameterName);
182 | 0 |
                             final MessageInfo messageInfo = e.getMessageInfo();
183 | 0 |
                             final ConversionFailure conversionFaiure = new ConversionFailure(
184 |  |
                                             parameterName, messageInfo, fieldInfo);
185 | 0 |
                             conversionFailures.add(conversionFaiure);
186 | 0 |
                             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 | 46 |
                     final Object dest = Array.newInstance(componentType, values.length);
210 | 139 |
                     for (int i = 0; i < values.length; i++) {
211 |  |
                             try {
212 | 93 |
                                     final Object convertedValue = convertToScalar(
213 |  |
                                                     converterProvider, values[i], componentType);
214 | 74 |
                                     Array.set(dest, i, convertedValue);
215 | 19 |
                             } catch (final ConversionException e) {
216 | 19 |
                                     final FieldInfo fieldInfo = new FieldInfo(parameterName, i);
217 | 19 |
                                     final MessageInfo messageInfo = e.getMessageInfo();
218 | 19 |
                                     final ConversionFailure conversionFaiure = new ConversionFailure(
219 |  |
                                                     parameterName, messageInfo, fieldInfo);
220 | 19 |
                                     conversionFailures.add(conversionFaiure);
221 | 74 |
                             }
222 |  |
                     }
223 | 46 |
                     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 | 4 |
                     if (parameterizedClassDesc != null
251 |  |
                                     && parameterizedClassDesc.isParameterizedClass()) {
252 | 4 |
                             final Class<?> destElementType = parameterizedClassDesc
253 |  |
                                             .getArguments()[0].getRawClass();
254 | 12 |
                             for (int i = 0; i < values.length; i++) {
255 | 8 |
                                     final Object value = values[i];
256 |  |
                                     try {
257 | 8 |
                                             final Object convertedValue = convertToScalar(
258 |  |
                                                             converterProvider, value, destElementType);
259 | 8 |
                                             collection.add(convertedValue);
260 | 0 |
                                     } catch (final ConversionException e) {
261 | 0 |
                                             collection.add(null);
262 | 0 |
                                             final FieldInfo fieldInfo = new FieldInfo(parameterName, i);
263 | 0 |
                                             final MessageInfo messageInfo = e.getMessageInfo();
264 | 0 |
                                             final ConversionFailure conversionFaiure = new ConversionFailure(
265 |  |
                                                             parameterName, messageInfo, fieldInfo);
266 | 0 |
                                             conversionFailures.add(conversionFaiure);
267 | 8 |
                                     }
268 |  |
                             }
269 | 4 |
                     } else {
270 | 0 |
                             for (final Object value : values) {
271 | 0 |
                                     collection.add(value);
272 |  |
                             }
273 |  |
                     }
274 | 4 |
             }
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 | 106 |
                     if (value == null) {
293 | 1 |
                             return null;
294 |  |
                     }
295 | 105 |
                     if (destClass.isAssignableFrom(value.getClass())) {
296 | 10 |
                             return value;
297 |  |
                     }
298 | 95 |
                     final Converter converter = converterProvider.getConverter(value
299 |  |
                                     .getClass(), destClass);
300 | 95 |
                     if (converter == null) {
301 | 0 |
                             return null;
302 |  |
                     }
303 | 95 |
                     return converter.convertToObject(value, destClass, conversionHelper);
304 |  |
             }
305 |  |
306 |  |
     }