/* * Copyright (c) 2001-2007, Inversoft Inc., All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ package org.primeframework.mvc.parameter.convert; import java.lang.reflect.Array; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.primeframework.mvc.util.TypeTools; /** * This class is the base type converter for all the type converters that handle Object types. If you are writing a * converter for primitive types, use the {@link org.primeframework.mvc.parameter.convert.converters.AbstractPrimitiveConverter} * class. * <p/> * This class mostly delegates between the various method calls by passing in default values or performing casting. * Each * method describes how it functions. * * @author Brian Pontarelli */ public abstract class AbstractGlobalConverter implements GlobalConverter { /** * Handles the following cases: * <p/> * <ul> * <li>Null - returns null</li> * <li>Type is an array - calls stringToArray</li> * <li>Type is not an array and values length is 1 or 0 - calls stringToObject</li> * <li>Type is an array and values length is > 1 - calls stringsToArray</li> * <li>Type is not an array and values length is > 1 - calls stringsToObject</li> * </ul> * * @param convertTo The type to convert to. * @param dynamicAttributes The dynamic attributes used to assist in conversion. * @param expression The full path to the expression that is causing the conversion. * @param values The values to convert. * @return The converted value. * @throws ConversionException If the conversion failed. * @throws ConverterStateException if the converter didn't have all of the information it needed to perform the * conversion. */ public Object convertFromStrings(Type convertTo, Map<String, String> dynamicAttributes, String expression, String... values) throws ConversionException, ConverterStateException { // Handle a zero or one String Class<?> rawType = TypeTools.rawType(convertTo); if (values == null || values.length <= 1) { String value = (values != null && values.length == 1) ? values[0] : null; if (rawType.isArray()) { // Punt on multi-dimensional arrays if (rawType.getComponentType().isArray()) { throw new ConverterStateException("Converter [" + getClass() + "] does not support" + " conversion to multi-dimensional arrays of type [" + convertTo + "]"); } return stringToArray(value, convertTo, dynamicAttributes, expression); } return stringToObject(value, convertTo, dynamicAttributes, expression); } // Handle multiple strings if (rawType.isArray()) { // Punt on multi-dimensional arrays if (rawType.getComponentType().isArray()) { throw new ConverterStateException("Converter [" + getClass() + "] does not support" + " conversion to multi-dimensional arrays of type [" + convertTo + "]"); } return stringsToArray(values, convertTo, dynamicAttributes, expression); } return stringsToObject(values, convertTo, dynamicAttributes, expression); } /** * Gets the first parameter type is the given type is a parametrized type. If it isn't, this returns null. If the * type * has multiple parameters, only the first is returned. * * @param type The type. * @return The first parameter type. */ protected Class<?> parameterType(Type type) { if (type instanceof ParameterizedType) { return (Class<?>) ((ParameterizedType) type).getActualTypeArguments()[0]; } return null; } /** * Converts the value to a String. * * @param convertFrom The original Type of the value. * @param dynamicAttributes The dynamic attributes used to assist in conversion. * @param expression The full path to the expression that is causing the conversion. * @param value The value to convert. * @return The converted value. * @throws ConversionException If the conversion failed. * @throws ConverterStateException if the converter didn't have all of the information it needed to perform the * conversion. */ public String convertToString(Type convertFrom, Map<String, String> dynamicAttributes, String expression, Object value) throws ConversionException { // Handle null if (value == null) { return null; } // Check simple conversion if (value instanceof String) { return (String) value; } // Handle arrays Class<?> rawType = TypeTools.rawType(convertFrom); if (rawType.isArray()) { return arrayToString(value, convertFrom, dynamicAttributes, expression); } return objectToString(value, convertFrom, dynamicAttributes, expression); } /** * This performs the conversion from a single String value to an array of the given type. * * @param value The value to convert to an array. * @param convertTo The array type to convert to. * @param dynamicAttributes The dynamic attributes used to assist in conversion. * @param expression The full path to the expression that is causing the conversion. * @return The converted value. * @throws ConversionException If the conversion failed. * @throws ConverterStateException if the converter didn't have all of the information it needed to perform the * conversion. */ protected Object stringToArray(String value, Type convertTo, Map<String, String> dynamicAttributes, String expression) throws ConversionException { if (value == null) { return null; } Object finalArray; Class<?> rawType = TypeTools.rawType(convertTo); if (StringUtils.isBlank(value)) { finalArray = Array.newInstance(rawType.getComponentType(), 0); } else { String[] parts = value.split(","); finalArray = Array.newInstance(rawType.getComponentType(), parts.length); for (int i = 0; i < parts.length; i++) { Object singleValue = stringToObject(parts[i], rawType.getComponentType(), dynamicAttributes, expression); Array.set(finalArray, i, singleValue); } } return finalArray; } /** * This performs the conversion from an array of String values to an array of the given type. * * @param values The values to convert to an array. * @param convertTo The array type to convert to. * @param dynamicAttributes The dynamic attributes to assist in the conversion. * @param expression The full path to the expression that is causing the conversion. * @return The converted value. * @throws ConversionException If the conversion failed. * @throws ConverterStateException if the converter didn't have all of the information it needed to perform the * conversion. */ protected Object stringsToArray(String[] values, Type convertTo, Map<String, String> dynamicAttributes, String expression) throws ConversionException { if (values == null) { return null; } Object finalArray; Class<?> rawType = TypeTools.rawType(convertTo); if (values.length == 0) { finalArray = Array.newInstance(rawType.getComponentType(), 0); } else { finalArray = Array.newInstance(rawType.getComponentType(), values.length); for (int i = 0; i < values.length; i++) { Object singleValue = stringToObject(values[i], rawType.getComponentType(), dynamicAttributes, expression); Array.set(finalArray, i, singleValue); } } return finalArray; } /** * This performs the conversion from an array to a single String value. * * @param value The array value to convert to a String. * @param convertFrom The array type to convert from. * @param dynamicAttributes The dynamic attributes to assist in the conversion. * @param expression The full path to the expression that is causing the conversion. * @return The converted value. * @throws ConversionException If the conversion failed. * @throws ConverterStateException if the converter didn't have all of the information it needed to perform the * conversion. */ protected String arrayToString(Object value, Type convertFrom, Map<String, String> dynamicAttributes, String expression) throws ConversionException { Class<?> rawType = TypeTools.rawType(convertFrom); if (!rawType.isArray()) { throw new ConversionException("The convertFrom parameter must be an array type"); } // if (value == null) { // return null; // } if (!value.getClass().isArray()) { throw new ConversionException("The value is not an array"); } if (value.getClass().getComponentType().isArray()) { throw new ConversionException("The value is a multi-dimensional array, which is not" + " supported by the AbstractConverter"); } int length = Array.getLength(value); StringBuilder str = new StringBuilder(); for (int i = 0; i < length; i++) { Object o = Array.get(value, i); str.append(convertToString(value.getClass().getComponentType(), dynamicAttributes, expression, o)); if (i + 1 < length) { str.append(","); } } return str.toString(); } /** * Converts the single String value to an Object. * * @param value The String value to convert. * @param convertTo The type to convert to. * @param dynamicAttributes The dynamic attributes to assist in the conversion. * @param expression The full path to the expression that is causing the conversion. * @return The converted value. * @throws ConversionException If the conversion failed. * @throws ConverterStateException if the converter didn't have all of the information it needed to perform the * conversion. */ protected abstract Object stringToObject(String value, Type convertTo, Map<String, String> dynamicAttributes, String expression) throws ConversionException, ConverterStateException; /** * Converts a String array to a single Object (not an array of Objects). Support for this method is uncommon. * * @param values The String values to convert. * @param convertTo The type to convert to. * @param dynamicAttributes The dynamic attributes to assist in the conversion. * @param expression The full path to the expression that is causing the conversion. * @return The converted value. * @throws ConversionException If the conversion failed. * @throws ConverterStateException if the converter didn't have all of the information it needed to perform the * conversion. */ protected abstract Object stringsToObject(String[] values, Type convertTo, Map<String, String> dynamicAttributes, String expression) throws ConversionException, ConverterStateException; /** * Converts the Object value to a String. * * @param value The Object value to convert. * @param convertFrom The type to convert from. * @param dynamicAttributes The dynamic attributes to assist in the conversion. * @param expression The full path to the expression that is causing the conversion. * @return The converted value. * @throws ConversionException If the conversion failed. * @throws ConverterStateException if the converter didn't have all of the information it needed to perform the * conversion. */ protected abstract String objectToString(Object value, Type convertFrom, Map<String, String> dynamicAttributes, String expression) throws ConversionException, ConverterStateException; }