package org.marketcetera.module;
import java.util.HashMap;
import java.util.Properties;
import org.apache.commons.beanutils.ConversionException;
import org.apache.commons.beanutils.ConvertUtilsBean;
import org.apache.commons.beanutils.Converter;
import org.marketcetera.core.Util;
import org.marketcetera.util.log.I18NBoundMessage1P;
import org.marketcetera.util.misc.ClassVersion;
import com.google.common.collect.Maps;
/* $License$ */
/**
* A Utility class to convert strings to object types.
* Following types of instances can be converted to from strings
* <ul>
* <li>Java Primtive Types</li>
* <li>BigDecimal</li>
* <li>BigInteger</li>
* <li>Strings</li>
* <li>File</li>
* <li>URL</li>
* <li>ModuleURN</li>
* </ul>
*
* This class is a thin wrapper around
* <a href="http://commons.apache.org/beanutils/apidocs/org/apache/commons/beanutils/ConvertUtilsBean.html">
* ConvertUtilsBean</a>
*
* @author anshul@marketcetera.com
* @version $Id: StringToTypeConverter.java 16841 2014-02-20 19:59:04Z colin $
* @since 1.0.0
*/
@ClassVersion("$Id: StringToTypeConverter.java 16841 2014-02-20 19:59:04Z colin $")
class StringToTypeConverter {
/**
* Returns true if conversion from the supplied type
* name is supported. The type name is either the name
* of the class or the name of one of the primitive types.
*
* If the supplied type name is not a valid java type, or
* if the class corresponding to the supplied java type
* cannot be loaded, a false value is returned.
*
* @param inTypeName the type name to check
*
* @return true if the converter supports conversion of strings
* to instances of the supplied type.
*/
public static boolean isSupported(String inTypeName) {
try {
return isSupported(toClass(inTypeName));
} catch (IllegalArgumentException ignored) {
}
return false;
}
/**
* Returns true if conversion from the supplied type
* is supported. The type name is either the name
* of the class or the name of one of the primitive types.
*
* @param inType the type to check
*
* @return true if the converter supports conversion of strings
* to instances of the supplied type.
*/
public static boolean isSupported(Class<?> inType) {
return sConverter.lookup(inType) != null;
}
/**
* Converts the supplied string value to the instance of the
* specified type.
*
* Calls to this method should only be made if {@link #isSupported(String)}
* returns true for the <code>inTypeName</code>, otherwise this method
* will throw an <code>IllegalArgumentException</code>.
*
* @param inTypeName the type of instance to return
* @param inValue the string value to convert to instance
*
* @return the instance converted from the string.
*
* @throws IllegalArgumentException if the supplied type name is
* not supported OR if there were errors converting
* the string to a numeric type.
*/
public static Object convert(String inTypeName, String inValue)
throws IllegalArgumentException {
return convert(toClass(inTypeName), inValue);
}
/**
* Converts the supplied string value to the instance of the
* specified type.
*
* Calls to this method should only be made if {@link #isSupported(String)}
* returns true for the <code>inTypeName</code>, otherwise this method
* will throw an <code>IllegalArgumentException</code>.
*
* @param inType the type of instance to return
* @param inValue the string value to convert to instance
*
* @return the instance converted from the string.
*
* @throws IllegalArgumentException if the supplied type name is
* not supported OR if there were errors converting
* the string to a numeric type.
*/
public static Object convert(Class<?> inType, String inValue)
throws IllegalArgumentException {
try {
return sConverter.convert(inValue, inType);
} catch (ConversionException e) {
throw new IllegalArgumentException(
Messages.STRING_CONVERSION_ERROR.getText(inValue,
inType.getName(),e.getMessage()));
}
}
/**
* Converts the supplied type name to class instance. This method
* ensures that the correct class objects are returned for primitive
* types.
*
* @param inTypeName the type name
*
* @return the class object corresponding to the type name.
*/
private static Class<?> toClass(String inTypeName) {
if(sPrimitiveTypeMap.containsKey(inTypeName)) {
return sPrimitiveTypeMap.get(inTypeName);
}
try {
return Class.forName(inTypeName);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException(inTypeName,e);
}
}
/**
* This method is used during class initialization to initialize
* the table for mapping primitive type names to their class instances.
*
* @param inClass the primitive type class to register.
*/
private static void registerPrimitive(Class<?> inClass) {
sPrimitiveTypeMap.put(inClass.getName(), inClass);
}
private static final ConvertUtilsBean sConverter = new ConvertUtilsBean();
private static final HashMap<String,Class<?>> sPrimitiveTypeMap = Maps.newHashMap();
/**
* A converter class for converting string to module URN.
*/
private static final class ModuleURNConverter implements Converter {
@SuppressWarnings("rawtypes")
public Object convert(Class inClass, Object o) {
if(ModuleURN.class.equals(inClass)) {
try {
if(o instanceof ModuleURN) {
return o;
} else if(o instanceof String) {
return new ModuleURN((String)o);
} else if(o != null) {
return new ModuleURN(o.toString());
}
} catch (IllegalArgumentException e) {
throw new ConversionException(new I18NBoundMessage1P(
Messages.CANNOT_CONVERT_TO_MODULE_URN,
o.toString()).getText(),e);
}
}
throw new ConversionException(new I18NBoundMessage1P(
Messages.CANNOT_CONVERT_TO_MODULE_URN,
o == null
? null
: o.toString()).getText());
}
}
private static final class PropertiesConverter implements Converter {
@SuppressWarnings("rawtypes")
public Object convert(Class inClass, Object o) {
if(Properties.class.equals(inClass)) {
if(o instanceof Properties) {
return o;
} else if(o instanceof String) {
return Util.propertiesFromString((String)o);
}
}
throw new ConversionException(new I18NBoundMessage1P(
Messages.CANNOT_CONVERT_TO_PROPERTIES,
o == null
? null
: o.toString()).getText());
}
}
static {
//Reset the converter to throw exceptions for conversion errors
sConverter.register(true, true, 0);
//register the module URN converter
sConverter.register(new ModuleURNConverter(), ModuleURN.class);
//register the Properties converter
sConverter.register(new PropertiesConverter(), Properties.class);
//initialize the table convert primitive type names to their
//respective class instances.
registerPrimitive(Boolean.TYPE);
registerPrimitive(Byte.TYPE);
registerPrimitive(Character.TYPE);
registerPrimitive(Short.TYPE);
registerPrimitive(Integer.TYPE);
registerPrimitive(Float.TYPE);
registerPrimitive(Long.TYPE);
registerPrimitive(Double.TYPE);
}
}