Coverage Report - org.seasar.cubby.controller.impl.RequestParameterBinderImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
RequestParameterBinderImpl
86%
69/80
76%
34/45
0
RequestParameterBinderImpl$1
100%
1/1
N/A
0
 
 1  
 /*
 2  
  * Copyright 2004-2008 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.controller.impl;
 17  
 
 18  
 import java.lang.reflect.Array;
 19  
 import java.lang.reflect.Field;
 20  
 import java.lang.reflect.Method;
 21  
 import java.util.ArrayList;
 22  
 import java.util.Collection;
 23  
 import java.util.LinkedHashSet;
 24  
 import java.util.List;
 25  
 import java.util.Map;
 26  
 import java.util.Set;
 27  
 import java.util.Map.Entry;
 28  
 
 29  
 import org.seasar.cubby.action.Action;
 30  
 import org.seasar.cubby.action.Form;
 31  
 import org.seasar.cubby.action.RequestParameter;
 32  
 import org.seasar.cubby.action.RequestParameterBindingType;
 33  
 import org.seasar.cubby.controller.RequestParameterBinder;
 34  
 import org.seasar.cubby.converter.ConversionHelper;
 35  
 import org.seasar.cubby.converter.Converter;
 36  
 import org.seasar.cubby.converter.ConverterFactory;
 37  
 import org.seasar.cubby.util.CubbyUtils;
 38  
 import org.seasar.framework.beans.BeanDesc;
 39  
 import org.seasar.framework.beans.ParameterizedClassDesc;
 40  
 import org.seasar.framework.beans.PropertyDesc;
 41  
 import org.seasar.framework.beans.factory.BeanDescFactory;
 42  
 
 43  
 /**
 44  
  * リクエストパラメータをオブジェクトへバインドするクラスの実装です。
 45  
  * 
 46  
  * @author baba
 47  
  * @since 1.1.0
 48  
  */
 49  82
 public class RequestParameterBinderImpl implements RequestParameterBinder {
 50  
 
 51  
         /** コンバータのファクトリクラス。 */
 52  
         private ConverterFactory converterFactory;
 53  
 
 54  
         /** 変換のヘルパクラス。 */
 55  
         private ConversionHelper conversionHelper;
 56  
 
 57  
         /**
 58  
          * コンバータのファクトリクラスを設定します。
 59  
          * 
 60  
          * @param converterFactory
 61  
          *            コンバータのファクトリクラス
 62  
          */
 63  
         public void setConverterFactory(final ConverterFactory converterFactory) {
 64  82
                 this.converterFactory = converterFactory;
 65  82
         }
 66  
 
 67  
         /**
 68  
          * 変換のヘルパクラスを設定します。
 69  
          * 
 70  
          * @param conversionHelper
 71  
          *            変換のヘルパクラス
 72  
          */
 73  
         public void setConversionHelper(final ConversionHelper conversionHelper) {
 74  82
                 this.conversionHelper = conversionHelper;
 75  82
         }
 76  
 
 77  
         /**
 78  
          * {@inheritDoc}
 79  
          */
 80  
         public void bind(final Map<String, Object[]> parameterMap,
 81  
                         final Object dest, final Class<? extends Action> actionClass,
 82  
                         final Method method) {
 83  16
                 if (parameterMap == null) {
 84  1
                         return;
 85  
                 }
 86  15
                 final BeanDesc destBeanDesc = BeanDescFactory.getBeanDesc(dest
 87  
                                 .getClass());
 88  15
                 for (final Entry<String, Object[]> entry : parameterMap.entrySet()) {
 89  71
                         final String sourceName = entry.getKey();
 90  71
                         if (destBeanDesc.hasPropertyDesc(sourceName)) {
 91  71
                                 final PropertyDesc destPropertyDesc = destBeanDesc
 92  
                                                 .getPropertyDesc(sourceName);
 93  71
                                 if (destPropertyDesc.isReadable()
 94  
                                                 && destPropertyDesc.isWritable()) {
 95  71
                                         if (!isBindToAllProperties(actionClass, method)) {
 96  6
                                                 final RequestParameter requestParameter = getRequestParameterAnnotation(destPropertyDesc);
 97  6
                                                 if (requestParameter == null) {
 98  3
                                                         continue;
 99  
                                                 }
 100  
                                         }
 101  
 
 102  
                                         try {
 103  68
                                                 final Object value = convert(entry.getValue(),
 104  
                                                                 destPropertyDesc);
 105  68
                                                 destPropertyDesc.setValue(dest, value);
 106  0
                                         } catch (final Exception e) {
 107  0
                                                 destPropertyDesc.setValue(dest, null);
 108  68
                                         }
 109  
                                 }
 110  
                         }
 111  68
                 }
 112  15
         }
 113  
 
 114  
         /**
 115  
          * 指定されたリクエストパラメータの値を出力先のプロパティの型に変換します。
 116  
          * 
 117  
          * @param values
 118  
          *            リクエストパラメータの値
 119  
          * @param destPropertyDesc
 120  
          *            出力先のプロパティの定義
 121  
          * @return 変換された値
 122  
          */
 123  
         private Object convert(final Object[] values,
 124  
                         final PropertyDesc destPropertyDesc) {
 125  68
                 final Class<?> destClass = destPropertyDesc.getPropertyType();
 126  
 
 127  68
                 final Converter converter = converterFactory.getConverter(values[0]
 128  
                                 .getClass(), destClass);
 129  68
                 if (converter != null) {
 130  27
                         return converter.convertToObject(values[0], destClass,
 131  
                                         conversionHelper);
 132  
                 }
 133  
 
 134  41
                 if (destClass.isArray()) {
 135  27
                         return convertToArray(values, destClass.getComponentType());
 136  
                 }
 137  14
                 if (List.class.isAssignableFrom(destClass)) {
 138  3
                         final List<Object> list = new ArrayList<Object>();
 139  3
                         convertToCollection(values, list, destPropertyDesc);
 140  3
                         return list;
 141  
                 }
 142  11
                 if (Set.class.isAssignableFrom(destClass)) {
 143  1
                         final Set<Object> set = new LinkedHashSet<Object>();
 144  1
                         convertToCollection(values, set, destPropertyDesc);
 145  1
                         return set;
 146  
                 }
 147  10
                 return convertToScalar(values[0], destClass);
 148  
         }
 149  
 
 150  
         /**
 151  
          * 指定された値を指定された要素の型の配列に変換します。
 152  
          * 
 153  
          * @param values
 154  
          *            変換する値
 155  
          * @param componentType
 156  
          *            要素の型
 157  
          * @return 変換後の値
 158  
          */
 159  
         private Object convertToArray(final Object[] values,
 160  
                         final Class<?> componentType) {
 161  27
                 final Object dest = Array.newInstance(componentType, values.length);
 162  82
                 for (int i = 0; i < values.length; i++) {
 163  55
                         final Object convertedValue = convertToScalar(values[i],
 164  
                                         componentType);
 165  55
                         Array.set(dest, i, convertedValue);
 166  
                 }
 167  27
                 return dest;
 168  
         }
 169  
 
 170  
         /**
 171  
          * 指定された値を変換してコレクションに追加します。
 172  
          * 
 173  
          * @param values
 174  
          *            変換する値
 175  
          * @param collection
 176  
          *            コレクション
 177  
          * @param propertyDesc
 178  
          *            プロパティの定義
 179  
          */
 180  
         private void convertToCollection(final Object[] values,
 181  
                         final Collection<Object> collection, final PropertyDesc propertyDesc) {
 182  4
                 if (propertyDesc.isParameterized()) {
 183  4
                         final ParameterizedClassDesc parameterizedClassDesc = propertyDesc
 184  
                                         .getParameterizedClassDesc();
 185  4
                         final Class<?> destElementType = parameterizedClassDesc
 186  
                                         .getArguments()[0].getRawClass();
 187  12
                         for (final Object value : values) {
 188  8
                                 final Object convertedValue = convertToScalar(value,
 189  
                                                 destElementType);
 190  8
                                 collection.add(convertedValue);
 191  
                         }
 192  4
                 } else {
 193  0
                         for (final Object value : values) {
 194  0
                                 collection.add(value);
 195  
                         }
 196  
                 }
 197  4
         }
 198  
 
 199  
         /**
 200  
          * 指定された値を指定された型に変換します。
 201  
          * 
 202  
          * @param value
 203  
          *            変換する値
 204  
          * @param destClass
 205  
          *            変換する型
 206  
          * @return 変換後の値
 207  
          */
 208  
         private Object convertToScalar(final Object value, final Class<?> destClass) {
 209  73
                 if (value == null) {
 210  1
                         return null;
 211  
                 }
 212  72
                 if (destClass.isAssignableFrom(value.getClass())) {
 213  15
                         return value;
 214  
                 }
 215  57
                 final Converter converter = converterFactory.getConverter(value
 216  
                                 .getClass(), destClass);
 217  57
                 if (converter == null) {
 218  0
                         return null;
 219  
                 }
 220  57
                 return converter.convertToObject(value, destClass, conversionHelper);
 221  
         }
 222  
 
 223  
         /**
 224  
          * 指定されたアクションメソッドを実行する際に、オブジェクトのすべてのプロパティにリクエストパラメータをバインドするかを示します。
 225  
          * 
 226  
          * @param method
 227  
          *            アクションメソッド
 228  
          * @return オブジェクトのすべてのプロパティにリクエストパラメータをバインドする場合は <code>true</code>、そうでない場合は
 229  
          *         <code>false</code>
 230  
          */
 231  
         private static boolean isBindToAllProperties(
 232  
                         final Class<? extends Action> actionClass, final Method method) {
 233  71
                 final Form form = CubbyUtils.getForm(actionClass, method);
 234  71
                 if (form == null) {
 235  2
                         return false;
 236  
                 }
 237  
 
 238  69
                 final RequestParameterBindingType type = form.bindingType();
 239  69
                 switch (type) {
 240  
                 case ALL_PROPERTIES:
 241  65
                         return true;
 242  
                 case ONLY_SPECIFIED_PROPERTIES:
 243  4
                         return false;
 244  
                 default:
 245  82
                         throw new IllegalStateException(type.toString());
 246  
                 }
 247  
         }
 248  
 
 249  
         /**
 250  
          * 指定されたプロパティから {@link RequestParameter} アノテーションを取得します。
 251  
          * 
 252  
          * @param propertyDesc
 253  
          *            プロパティの定義
 254  
          * @return {@link RequestParameter} アノテーション、指定されたプロパティが装飾されていない場合は
 255  
          *         <code>null</code>
 256  
          */
 257  
         private static RequestParameter getRequestParameterAnnotation(
 258  
                         final PropertyDesc propertyDesc) {
 259  
                 final RequestParameter request;
 260  6
                 if (propertyDesc.hasWriteMethod()) {
 261  0
                         final Method method = propertyDesc.getWriteMethod();
 262  0
                         if (method.isAnnotationPresent(RequestParameter.class)) {
 263  0
                                 request = method.getAnnotation(RequestParameter.class);
 264  
                         } else {
 265  0
                                 final Field field = propertyDesc.getField();
 266  0
                                 request = field.getAnnotation(RequestParameter.class);
 267  
                         }
 268  0
                 } else {
 269  6
                         final Field field = propertyDesc.getField();
 270  6
                         request = field.getAnnotation(RequestParameter.class);
 271  
                 }
 272  6
                 return request;
 273  
         }
 274  
 
 275  
 }