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 }