Mercurial > projects > dwt2
diff org.eclipse.core.databinding/src/org/eclipse/core/databinding/UpdateStrategy.d @ 78:0a55d2d5a946
Added file for databinding
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Tue, 14 Apr 2009 11:35:29 +0200 |
parents | |
children | 383ce7bd736b |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/org.eclipse.core.databinding/src/org/eclipse/core/databinding/UpdateStrategy.d Tue Apr 14 11:35:29 2009 +0200 @@ -0,0 +1,712 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Matt Carter - Bug 180392 + * - Character support completed (bug 197679) + *******************************************************************************/ + +module org.eclipse.core.databinding.UpdateStrategy; + +import java.lang.all; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.databinding.conversion.IConverter; +import org.eclipse.core.databinding.conversion.NumberToStringConverter; +import org.eclipse.core.databinding.conversion.StringToNumberConverter; +import org.eclipse.core.databinding.util.Policy; +import org.eclipse.core.internal.databinding.ClassLookupSupport; +import org.eclipse.core.internal.databinding.Pair; +import org.eclipse.core.internal.databinding.conversion.CharacterToStringConverter; +import org.eclipse.core.internal.databinding.conversion.IdentityConverter; +import org.eclipse.core.internal.databinding.conversion.IntegerToStringConverter; +import org.eclipse.core.internal.databinding.conversion.NumberToBigDecimalConverter; +import org.eclipse.core.internal.databinding.conversion.NumberToBigIntegerConverter; +import org.eclipse.core.internal.databinding.conversion.NumberToByteConverter; +import org.eclipse.core.internal.databinding.conversion.NumberToDoubleConverter; +import org.eclipse.core.internal.databinding.conversion.NumberToFloatConverter; +import org.eclipse.core.internal.databinding.conversion.NumberToIntegerConverter; +import org.eclipse.core.internal.databinding.conversion.NumberToLongConverter; +import org.eclipse.core.internal.databinding.conversion.NumberToShortConverter; +import org.eclipse.core.internal.databinding.conversion.ObjectToStringConverter; +import org.eclipse.core.internal.databinding.conversion.StringToByteConverter; +import org.eclipse.core.internal.databinding.conversion.StringToCharacterConverter; +import org.eclipse.core.internal.databinding.conversion.StringToShortConverter; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; + +import com.ibm.icu.text.NumberFormat; + +/** + * @since 1.0 + * + */ +/* package */class UpdateStrategy { + + private static final String BOOLEAN_TYPE = "java.lang.Boolean.TYPE"; //$NON-NLS-1$ + + private static final String SHORT_TYPE = "java.lang.Short.TYPE"; //$NON-NLS-1$ + + private static final String BYTE_TYPE = "java.lang.Byte.TYPE"; //$NON-NLS-1$ + + private static final String DOUBLE_TYPE = "java.lang.Double.TYPE"; //$NON-NLS-1$ + + private static final String FLOAT_TYPE = "java.lang.Float.TYPE"; //$NON-NLS-1$ + + private static final String INTEGER_TYPE = "java.lang.Integer.TYPE"; //$NON-NLS-1$ + + private static final String LONG_TYPE = "java.lang.Long.TYPE"; //$NON-NLS-1$ + + private static final String CHARACTER_TYPE = "java.lang.Character.TYPE"; //$NON-NLS-1$ + + private static Map converterMap; + + private static ClassInfo autoboxed(ClassInfo clazz) { + if (clazz is Float.TYPE) + return Float.classinfo; + else if (clazz is Double.TYPE) + return Double.classinfo; + else if (clazz is Short.TYPE) + return Short.classinfo; + else if (clazz is Integer.TYPE) + return Integer.classinfo; + else if (clazz is Long.TYPE) + return Long.classinfo; + else if (clazz is Byte.TYPE) + return Byte.classinfo; + else if (clazz is Boolean.TYPE) + return Boolean.classinfo; + else if (clazz is Character.TYPE) + return Character.classinfo; + return clazz; + } + + final protected void checkAssignable(Object toType, Object fromType, + String errorString) { + Boolean assignableFromModelToModelConverter = isAssignableFromTo( + fromType, toType); + if (assignableFromModelToModelConverter !is null + && !assignableFromModelToModelConverter.booleanValue()) { + throw new BindingException(errorString + + " Expected: " + fromType + ", actual: " + toType); //$NON-NLS-1$//$NON-NLS-2$ + } + } + + /** + * Tries to create a converter that can convert from values of type + * fromType. Returns <code>null</code> if no converter could be created. + * Either toType or modelDescription can be <code>null</code>, but not + * both. + * + * @param fromType + * @param toType + * @return an IConverter, or <code>null</code> if unsuccessful + */ + protected IConverter createConverter(Object fromType, Object toType) { + if (!( null !is cast(ClassInfo)fromType ) || !( null !is cast(ClassInfo)toType )) { + return new DefaultConverter(fromType, toType); + } + ClassInfo toClass = cast(ClassInfo) toType; + ClassInfo originalToClass = toClass; + if (toClass.isPrimitive()) { + toClass = autoboxed(toClass); + } + ClassInfo fromClass = cast(ClassInfo) fromType; + ClassInfo originalFromClass = fromClass; + if (fromClass.isPrimitive()) { + fromClass = autoboxed(fromClass); + } + if (!(cast(ClassInfo) toType).isPrimitive() + && toClass.isAssignableFrom(fromClass)) { + return new IdentityConverter(originalFromClass, originalToClass); + } + if ((cast(ClassInfo) fromType).isPrimitive() && (cast(ClassInfo) toType).isPrimitive() + && fromType.equals(toType)) { + return new IdentityConverter(originalFromClass, originalToClass); + } + Map converterMap = getConverterMap(); + ClassInfo[] supertypeHierarchyFlattened = ClassLookupSupport + .getTypeHierarchyFlattened(fromClass); + for (int i = 0; i < supertypeHierarchyFlattened.length; i++) { + ClassInfo currentFromClass = supertypeHierarchyFlattened[i]; + if (currentFromClass is toType) { + // converting to toType is just a widening + return new IdentityConverter(fromClass, toClass); + } + Pair key = new Pair(getKeyForClass(fromType, currentFromClass), + getKeyForClass(toType, toClass)); + Object converterOrClassname = converterMap.get(key); + if ( null !is cast(IConverter)converterOrClassname ) { + return cast(IConverter) converterOrClassname; + } else if ( null !is cast(String)converterOrClassname ) { + String classname = cast(String) converterOrClassname; + ClassInfo converterClass; + try { + converterClass = ClassInfo.forName(classname); + IConverter result = cast(IConverter) converterClass + .newInstance(); + converterMap.put(key, result); + return result; + } catch (Exception e) { + Policy + .getLog() + .log( + new Status( + IStatus.ERROR, + Policy.JFACE_DATABINDING, + 0, + "Error while instantiating default converter", e)); //$NON-NLS-1$ + } + } + } + // Since we found no converter yet, try a "downcast" converter; + // the IdentityConverter will automatically check the actual types at + // runtime. + if (fromClass.isAssignableFrom(toClass)) { + return new IdentityConverter(originalFromClass, originalToClass); + } + return new DefaultConverter(fromType, toType); + } + + private synchronized static Map getConverterMap() { + // using string-based lookup avoids loading of too many classes + if (converterMap is null) { + // NumberFormat to be shared across converters for the formatting of + // integer values + NumberFormat integerFormat = NumberFormat.getIntegerInstance(); + // NumberFormat to be shared across converters for formatting non + // integer values + NumberFormat numberFormat = NumberFormat.getNumberInstance(); + + converterMap = new HashMap(); + // Standard and Boxed Types + converterMap + .put( + new Pair("java.util.Date", "java.lang.String"), "org.eclipse.core.internal.databinding.conversion.DateToStringConverter"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + converterMap + .put( + new Pair("java.lang.String", "java.lang.Boolean"), "org.eclipse.core.internal.databinding.conversion.StringToBooleanConverter"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + converterMap + .put( + new Pair("java.lang.String", "java.lang.Byte"), StringToByteConverter.toByte(integerFormat, false)); //$NON-NLS-1$//$NON-NLS-2$ + converterMap + .put( + new Pair("java.lang.String", "java.util.Date"), "org.eclipse.core.internal.databinding.conversion.StringToDateConverter"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + converterMap + .put( + new Pair("java.lang.String", "java.lang.Short"), StringToShortConverter.toShort(integerFormat, false)); //$NON-NLS-1$//$NON-NLS-2$ + converterMap + .put( + new Pair("java.lang.String", "java.lang.Character"), StringToCharacterConverter.toCharacter(false)); //$NON-NLS-1$//$NON-NLS-2$ + converterMap + .put( + new Pair("java.lang.String", "java.lang.Integer"), StringToNumberConverter.toInteger(integerFormat, false)); //$NON-NLS-1$//$NON-NLS-2$ + converterMap + .put( + new Pair("java.lang.String", "java.lang.Double"), StringToNumberConverter.toDouble(numberFormat, false)); //$NON-NLS-1$//$NON-NLS-2$ + converterMap + .put( + new Pair("java.lang.String", "java.lang.Long"), StringToNumberConverter.toLong(integerFormat, false)); //$NON-NLS-1$//$NON-NLS-2$ + converterMap + .put( + new Pair("java.lang.String", "java.lang.Float"), StringToNumberConverter.toFloat(numberFormat, false)); //$NON-NLS-1$//$NON-NLS-2$ + converterMap + .put( + new Pair("java.lang.String", "java.math.BigInteger"), StringToNumberConverter.toBigInteger(integerFormat)); //$NON-NLS-1$//$NON-NLS-2$ + converterMap + .put( + new Pair("java.lang.Integer", "java.lang.String"), NumberToStringConverter.fromInteger(integerFormat, false)); //$NON-NLS-1$//$NON-NLS-2$ + converterMap + .put( + new Pair("java.lang.Long", "java.lang.String"), NumberToStringConverter.fromLong(integerFormat, false)); //$NON-NLS-1$//$NON-NLS-2$ + converterMap + .put( + new Pair("java.lang.Double", "java.lang.String"), NumberToStringConverter.fromDouble(numberFormat, false)); //$NON-NLS-1$//$NON-NLS-2$ + converterMap + .put( + new Pair("java.lang.Float", "java.lang.String"), NumberToStringConverter.fromFloat(numberFormat, false)); //$NON-NLS-1$//$NON-NLS-2$ + converterMap + .put( + new Pair("java.math.BigInteger", "java.lang.String"), NumberToStringConverter.fromBigInteger(integerFormat)); //$NON-NLS-1$//$NON-NLS-2$ + converterMap + .put( + new Pair("java.lang.Byte", "java.lang.String"), IntegerToStringConverter.fromByte(integerFormat, false)); //$NON-NLS-1$//$NON-NLS-2$ + converterMap + .put( + new Pair("java.lang.Short", "java.lang.String"), IntegerToStringConverter.fromShort(integerFormat, false)); //$NON-NLS-1$//$NON-NLS-2$ + converterMap + .put( + new Pair("java.lang.Character", "java.lang.String"), CharacterToStringConverter.fromCharacter(false)); //$NON-NLS-1$//$NON-NLS-2$ + + converterMap + .put( + new Pair("java.lang.Object", "java.lang.String"), "org.eclipse.core.internal.databinding.conversion.ObjectToStringConverter"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + + // Integer.TYPE + converterMap + .put( + new Pair("java.lang.String", INTEGER_TYPE), StringToNumberConverter.toInteger(integerFormat, true)); //$NON-NLS-1$ + converterMap + .put( + new Pair(INTEGER_TYPE, "java.lang.Integer"), new IdentityConverter(Integer.TYPE, Integer.classinfo)); //$NON-NLS-1$ + converterMap + .put( + new Pair(INTEGER_TYPE, "java.lang.Object"), new IdentityConverter(Integer.TYPE, Object.classinfo)); //$NON-NLS-1$ + converterMap + .put( + new Pair(INTEGER_TYPE, "java.lang.String"), NumberToStringConverter.fromInteger(integerFormat, true)); //$NON-NLS-1$ + + // Byte.TYPE + converterMap + .put( + new Pair("java.lang.String", BYTE_TYPE), StringToByteConverter.toByte(integerFormat, true)); //$NON-NLS-1$ + converterMap + .put( + new Pair(BYTE_TYPE, "java.lang.Byte"), new IdentityConverter(Byte.TYPE, Byte.classinfo)); //$NON-NLS-1$ + converterMap + .put( + new Pair(BYTE_TYPE, "java.lang.String"), IntegerToStringConverter.fromByte(integerFormat, true)); //$NON-NLS-1$ + converterMap + .put( + new Pair(BYTE_TYPE, "java.lang.Object"), new IdentityConverter(Byte.TYPE, Object.classinfo)); //$NON-NLS-1$ + + // Double.TYPE + converterMap + .put( + new Pair("java.lang.String", DOUBLE_TYPE), StringToNumberConverter.toDouble(numberFormat, true)); //$NON-NLS-1$ + converterMap + .put( + new Pair(DOUBLE_TYPE, "java.lang.String"), NumberToStringConverter.fromDouble(numberFormat, true)); //$NON-NLS-1$ + + converterMap + .put( + new Pair(DOUBLE_TYPE, "java.lang.Double"), new IdentityConverter(Double.TYPE, Double.classinfo)); //$NON-NLS-1$ + converterMap + .put( + new Pair(DOUBLE_TYPE, "java.lang.Object"), new IdentityConverter(Double.TYPE, Object.classinfo)); //$NON-NLS-1$ + + // Boolean.TYPE + converterMap + .put( + new Pair("java.lang.String", BOOLEAN_TYPE), "org.eclipse.core.internal.databinding.conversion.StringToBooleanPrimitiveConverter"); //$NON-NLS-1$ //$NON-NLS-2$ + converterMap + .put( + new Pair(BOOLEAN_TYPE, "java.lang.Boolean"), new IdentityConverter(Boolean.TYPE, Boolean.classinfo)); //$NON-NLS-1$ + converterMap + .put( + new Pair(BOOLEAN_TYPE, "java.lang.String"), new ObjectToStringConvertercast(Boolean.TYPE)); //$NON-NLS-1$ + converterMap + .put( + new Pair(BOOLEAN_TYPE, "java.lang.Object"), new IdentityConverter(Boolean.TYPE, Object.classinfo)); //$NON-NLS-1$ + + // Float.TYPE + converterMap + .put( + new Pair("java.lang.String", FLOAT_TYPE), StringToNumberConverter.toFloat(numberFormat, true)); //$NON-NLS-1$ + converterMap + .put( + new Pair(FLOAT_TYPE, "java.lang.String"), NumberToStringConverter.fromFloat(numberFormat, true)); //$NON-NLS-1$ + converterMap + .put( + new Pair(FLOAT_TYPE, "java.lang.Float"), new IdentityConverter(Float.TYPE, Float.classinfo)); //$NON-NLS-1$ + converterMap + .put( + new Pair(FLOAT_TYPE, "java.lang.Object"), new IdentityConverter(Float.TYPE, Object.classinfo)); //$NON-NLS-1$ + + // Short.TYPE + converterMap + .put( + new Pair("java.lang.String", SHORT_TYPE), StringToShortConverter.toShort(integerFormat, true)); //$NON-NLS-1$ + converterMap + .put( + new Pair(SHORT_TYPE, "java.lang.Short"), new IdentityConverter(Short.TYPE, Short.classinfo)); //$NON-NLS-1$ + converterMap + .put( + new Pair(SHORT_TYPE, "java.lang.String"), IntegerToStringConverter.fromShort(integerFormat, true)); //$NON-NLS-1$ + converterMap + .put( + new Pair(SHORT_TYPE, "java.lang.Object"), new IdentityConverter(Short.TYPE, Object.classinfo)); //$NON-NLS-1$ + + // Long.TYPE + converterMap + .put( + new Pair("java.lang.String", LONG_TYPE), StringToNumberConverter.toLong(integerFormat, true)); //$NON-NLS-1$ + converterMap + .put( + new Pair(LONG_TYPE, "java.lang.String"), NumberToStringConverter.fromLong(integerFormat, true)); //$NON-NLS-1$ + converterMap + .put( + new Pair(LONG_TYPE, "java.lang.Long"), new IdentityConverter(Long.TYPE, Long.classinfo)); //$NON-NLS-1$ + converterMap + .put( + new Pair(LONG_TYPE, "java.lang.Object"), new IdentityConverter(Long.TYPE, Object.classinfo)); //$NON-NLS-1$ + + // Character.TYPE + converterMap + .put( + new Pair("java.lang.String", CHARACTER_TYPE), StringToCharacterConverter.toCharacter(true)); //$NON-NLS-1$ + converterMap + .put( + new Pair(CHARACTER_TYPE, "java.lang.Character"), new IdentityConverter(Character.TYPE, Character.classinfo)); //$NON-NLS-1$ + converterMap + .put( + new Pair(CHARACTER_TYPE, "java.lang.String"), CharacterToStringConverter.fromCharacter(true)); //$NON-NLS-1$ + converterMap + .put( + new Pair(CHARACTER_TYPE, "java.lang.Object"), new IdentityConverter(Character.TYPE, Object.classinfo)); //$NON-NLS-1$ + + // Miscellaneous + converterMap + .put( + new Pair( + "org.eclipse.core.runtime.IStatus", "java.lang.String"), "org.eclipse.core.internal.databinding.conversion.StatusToStringConverter"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + + addNumberToByteConverters(converterMap, integerFormat, + integerClasses); + addNumberToByteConverters(converterMap, numberFormat, floatClasses); + + addNumberToShortConverters(converterMap, integerFormat, + integerClasses); + addNumberToShortConverters(converterMap, numberFormat, floatClasses); + + addNumberToIntegerConverters(converterMap, integerFormat, + integerClasses); + addNumberToIntegerConverters(converterMap, numberFormat, + floatClasses); + + addNumberToLongConverters(converterMap, integerFormat, + integerClasses); + addNumberToLongConverters(converterMap, numberFormat, floatClasses); + + addNumberToFloatConverters(converterMap, integerFormat, + integerClasses); + addNumberToFloatConverters(converterMap, numberFormat, floatClasses); + + addNumberToDoubleConverters(converterMap, integerFormat, + integerClasses); + addNumberToDoubleConverters(converterMap, numberFormat, + floatClasses); + + addNumberToBigIntegerConverters(converterMap, integerFormat, + integerClasses); + addNumberToBigIntegerConverters(converterMap, numberFormat, + floatClasses); + + addNumberToBigDecimalConverters(converterMap, integerFormat, + integerClasses); + addNumberToBigDecimalConverters(converterMap, numberFormat, + floatClasses); + } + + return converterMap; + } + + private static final ClassInfo[] integerClasses = new ClassInfo[] [ Byte.TYPE, + Byte.classinfo, Short.TYPE, Short.classinfo, Integer.TYPE, Integer.classinfo, + Long.TYPE, Long.classinfo, BigInteger.classinfo ]; + + private static final ClassInfo[] floatClasses = new ClassInfo[] [ Float.TYPE, + Float.classinfo, Double.TYPE, Double.classinfo, BigDecimal.classinfo ]; + + /** + * Registers converters to boxed and unboxed types from a list of from + * classes. + * + * @param map + * @param numberFormat + * @param fromTypes + */ + private static void addNumberToByteConverters(Map map, + NumberFormat numberFormat, ClassInfo[] fromTypes) { + + for (int i = 0; i < fromTypes.length; i++) { + ClassInfo fromType = fromTypes[i]; + if (!fromType.equals(Byte.classinfo) && !fromType.equalscast(Byte.TYPE)) { + String fromName = (fromType.isPrimitive()) ? getKeyForClass( + fromType, null) : fromType.getName(); + + map + .put(new Pair(fromName, BYTE_TYPE), + new NumberToByteConverter(numberFormat, + fromType, true)); + map + .put(new Pair(fromName, Byte.classinfo.getName()), + new NumberToByteConverter(numberFormat, + fromType, false)); + } + } + } + + /** + * Registers converters to boxed and unboxed types from a list of from + * classes. + * + * @param map + * @param numberFormat + * @param fromTypes + */ + private static void addNumberToShortConverters(Map map, + NumberFormat numberFormat, ClassInfo[] fromTypes) { + for (int i = 0; i < fromTypes.length; i++) { + ClassInfo fromType = fromTypes[i]; + if (!fromType.equals(Short.classinfo) && !fromType.equalscast(Short.TYPE)) { + String fromName = (fromType.isPrimitive()) ? getKeyForClass( + fromType, null) : fromType.getName(); + + map + .put(new Pair(fromName, SHORT_TYPE), + new NumberToShortConverter(numberFormat, + fromType, true)); + map.put(new Pair(fromName, Short.classinfo.getName()), + new NumberToShortConverter(numberFormat, fromType, + false)); + } + } + } + + /** + * Registers converters to boxed and unboxed types from a list of from + * classes. + * + * @param map + * @param numberFormat + * @param fromTypes + */ + private static void addNumberToIntegerConverters(Map map, + NumberFormat numberFormat, ClassInfo[] fromTypes) { + for (int i = 0; i < fromTypes.length; i++) { + ClassInfo fromType = fromTypes[i]; + if (!fromType.equals(Integer.classinfo) + && !fromType.equalscast(Integer.TYPE)) { + String fromName = (fromType.isPrimitive()) ? getKeyForClass( + fromType, null) : fromType.getName(); + + map.put(new Pair(fromName, INTEGER_TYPE), + new NumberToIntegerConverter(numberFormat, fromType, + true)); + map.put(new Pair(fromName, Integer.classinfo.getName()), + new NumberToIntegerConverter(numberFormat, fromType, + false)); + } + } + } + + /** + * Registers converters to boxed and unboxed types from a list of from + * classes. + * + * @param map + * @param numberFormat + * @param fromTypes + */ + private static void addNumberToLongConverters(Map map, + NumberFormat numberFormat, ClassInfo[] fromTypes) { + for (int i = 0; i < fromTypes.length; i++) { + ClassInfo fromType = fromTypes[i]; + if (!fromType.equals(Long.classinfo) && !fromType.equalscast(Long.TYPE)) { + String fromName = (fromType.isPrimitive()) ? getKeyForClass( + fromType, null) : fromType.getName(); + + map + .put(new Pair(fromName, LONG_TYPE), + new NumberToLongConverter(numberFormat, + fromType, true)); + map + .put(new Pair(fromName, Long.classinfo.getName()), + new NumberToLongConverter(numberFormat, + fromType, false)); + } + } + } + + /** + * Registers converters to boxed and unboxed types from a list of from + * classes. + * + * @param map + * @param numberFormat + * @param fromTypes + */ + private static void addNumberToFloatConverters(Map map, + NumberFormat numberFormat, ClassInfo[] fromTypes) { + for (int i = 0; i < fromTypes.length; i++) { + ClassInfo fromType = fromTypes[i]; + if (!fromType.equals(Float.classinfo) && !fromType.equalscast(Float.TYPE)) { + String fromName = (fromType.isPrimitive()) ? getKeyForClass( + fromType, null) : fromType.getName(); + + map + .put(new Pair(fromName, FLOAT_TYPE), + new NumberToFloatConverter(numberFormat, + fromType, true)); + map.put(new Pair(fromName, Float.classinfo.getName()), + new NumberToFloatConverter(numberFormat, fromType, + false)); + } + } + } + + /** + * Registers converters to boxed and unboxed types from a list of from + * classes. + * + * @param map + * @param numberFormat + * @param fromTypes + */ + private static void addNumberToDoubleConverters(Map map, + NumberFormat numberFormat, ClassInfo[] fromTypes) { + for (int i = 0; i < fromTypes.length; i++) { + ClassInfo fromType = fromTypes[i]; + if (!fromType.equals(Double.classinfo) && !fromType.equalscast(Double.TYPE)) { + String fromName = (fromType.isPrimitive()) ? getKeyForClass( + fromType, null) : fromType.getName(); + + map.put(new Pair(fromName, DOUBLE_TYPE), + new NumberToDoubleConverter(numberFormat, fromType, + true)); + map.put(new Pair(fromName, Double.classinfo.getName()), + new NumberToDoubleConverter(numberFormat, fromType, + false)); + } + } + } + + /** + * Registers converters to boxed and unboxed types from a list of from + * classes. + * + * @param map + * @param numberFormat + * @param fromTypes + */ + private static void addNumberToBigIntegerConverters(Map map, + NumberFormat numberFormat, ClassInfo[] fromTypes) { + for (int i = 0; i < fromTypes.length; i++) { + ClassInfo fromType = fromTypes[i]; + if (!fromType.equals(BigInteger.classinfo)) { + String fromName = (fromType.isPrimitive()) ? getKeyForClass( + fromType, null) : fromType.getName(); + + map + .put(new Pair(fromName, BigInteger.classinfo.getName()), + new NumberToBigIntegerConverter(numberFormat, + fromType)); + } + } + } + + /** + * Registers converters to boxed and unboxed types from a list of from + * classes. + * + * @param map + * @param numberFormat + * @param fromTypes + */ + private static void addNumberToBigDecimalConverters(Map map, + NumberFormat numberFormat, ClassInfo[] fromTypes) { + for (int i = 0; i < fromTypes.length; i++) { + ClassInfo fromType = fromTypes[i]; + if (!fromType.equals(BigDecimal.classinfo)) { + String fromName = (fromType.isPrimitive()) ? getKeyForClass( + fromType, null) : fromType.getName(); + + map + .put(new Pair(fromName, BigDecimal.classinfo.getName()), + new NumberToBigDecimalConverter(numberFormat, + fromType)); + } + } + } + + private static String getKeyForClass(Object originalValue, + ClassInfo filteredValue) { + if ( null !is cast(ClassInfo)originalValue ) { + ClassInfo originalClass = cast(ClassInfo) originalValue; + if (originalClass.equalscast(Integer.TYPE)) { + return INTEGER_TYPE; + } else if (originalClass.equalscast(Byte.TYPE)) { + return BYTE_TYPE; + } else if (originalClass.equalscast(Boolean.TYPE)) { + return BOOLEAN_TYPE; + } else if (originalClass.equalscast(Double.TYPE)) { + return DOUBLE_TYPE; + } else if (originalClass.equalscast(Float.TYPE)) { + return FLOAT_TYPE; + } else if (originalClass.equalscast(Long.TYPE)) { + return LONG_TYPE; + } else if (originalClass.equalscast(Short.TYPE)) { + return SHORT_TYPE; + } + } + return filteredValue.getName(); + } + + /** + * Returns {@link Boolean#TRUE} if the from type is assignable to the to + * type, or {@link Boolean#FALSE} if it not, or <code>null</code> if + * unknown. + * + * @param fromType + * @param toType + * @return whether fromType is assignable to toType, or <code>null</code> + * if unknown + */ + protected Boolean isAssignableFromTo(Object fromType, Object toType) { + if ( null !is cast(ClassInfo )fromType && null !is cast(ClassInfo)toType ) { + ClassInfo toClass = cast(ClassInfo) toType; + if (toClass.isPrimitive()) { + toClass = autoboxed(toClass); + } + ClassInfo fromClass = cast(ClassInfo) fromType; + if (fromClass.isPrimitive()) { + fromClass = autoboxed(fromClass); + } + return toClass.isAssignableFrom(fromClass) ? Boolean.TRUE + : Boolean.FALSE; + } + return null; + } + + /* + * Default converter implementation, does not perform any conversion. + */ + protected static final class DefaultConverter : IConverter { + + private final Object toType; + + private final Object fromType; + + /** + * @param fromType + * @param toType + */ + this(Object fromType, Object toType) { + this.toType = toType; + this.fromType = fromType; + } + + public Object convert(Object fromObject) { + return fromObject; + } + + public Object getFromType() { + return fromType; + } + + public Object getToType() { + return toType; + } + } + +}