Author: oheger
Date: Sun Oct 20 20:26:26 2013
New Revision: 1533966

URL: http://svn.apache.org/r1533966
Log:
Generified AbstractConverter.

AbstractConverter now implements the generified convert() method. It now has a
generic parameter for its default type. This commit also fixes
[BEANUTILS-445].

Modified:
    
commons/proper/beanutils/branches/java5/src/main/java/org/apache/commons/beanutils/BeanUtilsBean.java
    
commons/proper/beanutils/branches/java5/src/main/java/org/apache/commons/beanutils/converters/AbstractConverter.java

Modified: 
commons/proper/beanutils/branches/java5/src/main/java/org/apache/commons/beanutils/BeanUtilsBean.java
URL: 
http://svn.apache.org/viewvc/commons/proper/beanutils/branches/java5/src/main/java/org/apache/commons/beanutils/BeanUtilsBean.java?rev=1533966&r1=1533965&r2=1533966&view=diff
==============================================================================
--- 
commons/proper/beanutils/branches/java5/src/main/java/org/apache/commons/beanutils/BeanUtilsBean.java
 (original)
+++ 
commons/proper/beanutils/branches/java5/src/main/java/org/apache/commons/beanutils/BeanUtilsBean.java
 Sun Oct 20 20:26:26 2013
@@ -381,7 +381,7 @@ public class BeanUtilsBean {
             if (dynaProperty == null) {
                 return; // Skip this property setter
             }
-            type = dynaProperty.getType();
+            type = dynaPropertyType(dynaProperty, value);
         } else {
             PropertyDescriptor descriptor = null;
             try {
@@ -918,7 +918,7 @@ public class BeanUtilsBean {
             if (dynaProperty == null) {
                 return; // Skip this property setter
             }
-            type = dynaProperty.getType();
+            type = dynaPropertyType(dynaProperty, value);
         } else if (target instanceof Map) {
             type = Object.class;
         } else if (target != null && target.getClass().isArray() && index >= 
0) {
@@ -1102,4 +1102,20 @@ public class BeanUtilsBean {
             return null;
         }
     }
+
+    /**
+     * Determines the type of a {@code DynaProperty}. Here a special treatment
+     * is needed for mapped properties.
+     *
+     * @param dynaProperty the property descriptor
+     * @param value the value object to be set for this property
+     * @return the type of this property
+     */
+    private static Class<?> dynaPropertyType(DynaProperty dynaProperty,
+            Object value) {
+        if (!dynaProperty.isMapped()) {
+            return dynaProperty.getType();
+        }
+        return (value == null) ? String.class : value.getClass();
+    }
 }

Modified: 
commons/proper/beanutils/branches/java5/src/main/java/org/apache/commons/beanutils/converters/AbstractConverter.java
URL: 
http://svn.apache.org/viewvc/commons/proper/beanutils/branches/java5/src/main/java/org/apache/commons/beanutils/converters/AbstractConverter.java?rev=1533966&r1=1533965&r2=1533966&view=diff
==============================================================================
--- 
commons/proper/beanutils/branches/java5/src/main/java/org/apache/commons/beanutils/converters/AbstractConverter.java
 (original)
+++ 
commons/proper/beanutils/branches/java5/src/main/java/org/apache/commons/beanutils/converters/AbstractConverter.java
 Sun Oct 20 20:26:26 2013
@@ -18,11 +18,12 @@ package org.apache.commons.beanutils.con
 
 import java.lang.reflect.Array;
 import java.util.Collection;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+
 import org.apache.commons.beanutils.BeanUtils;
 import org.apache.commons.beanutils.ConversionException;
 import org.apache.commons.beanutils.Converter;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 
 /**
  * Base {@link Converter} implementation that provides the structure
@@ -43,11 +44,18 @@ import org.apache.commons.beanutils.Conv
  *     <li><code>convertToType(Class, value)</code> - convert
  *         to the specified type</li>
  * </ul>
+ * <p>
+ * The default value has to be compliant to the default type of this
+ * converter - which is enforced by the generic type parameter. If a
+ * conversion is not possible and a default value is set, the converter
+ * tries to transform the default value to the requested target type.
+ * If this fails, a {@code ConversionException} if thrown.
  *
+ * @param <D> the default conversion target type of this converter
  * @version $Id$
  * @since 1.8.0
  */
-public abstract class AbstractConverter implements Converter {
+public abstract class AbstractConverter<D> implements Converter {
 
     /** Debug logging message to indicate default value configuration */
     private static final String DEFAULT_CONFIG_MSG =
@@ -71,7 +79,7 @@ public abstract class AbstractConverter 
     /**
      * The default value specified to our Constructor, if any.
      */
-    private Object defaultValue = null;
+    private D defaultValue = null;
 
     // ----------------------------------------------------------- Constructors
 
@@ -90,7 +98,7 @@ public abstract class AbstractConverter 
      * if the value to be converted is missing or an error
      * occurs converting the value.
      */
-    public AbstractConverter(Object defaultValue) {
+    public AbstractConverter(D defaultValue) {
         setDefaultValue(defaultValue);
     }
 
@@ -112,16 +120,21 @@ public abstract class AbstractConverter 
      * Convert the input object into an output object of the
      * specified type.
      *
+     * @param <T> the target type of the conversion
      * @param type Data type to which this value should be converted
      * @param value The input value to be converted
      * @return The converted value.
      * @throws ConversionException if conversion cannot be performed
      * successfully and no default is specified.
      */
-    public Object convert(Class type, Object value) {
+    public <T> T convert(Class<T> type, Object value) {
 
-        Class sourceType  = value == null ? null : value.getClass();
-        Class targetType  = primitive(type  == null ? getDefaultType() : type);
+        if (type == null) {
+            return convertToDefaultType(value);
+        }
+
+        Class<?> sourceType  = value == null ? null : value.getClass();
+        Class<T> targetType  = primitive(type);
 
         if (log().isDebugEnabled()) {
             log().debug("Converting"
@@ -141,7 +154,7 @@ public abstract class AbstractConverter 
         try {
             // Convert --> String
             if (targetType.equals(String.class)) {
-                return convertToString(value);
+                return targetType.cast(convertToString(value));
 
             // No conversion necessary
             } else if (targetType.equals(sourceType)) {
@@ -149,7 +162,7 @@ public abstract class AbstractConverter 
                     log().debug("    No conversion required, value is already 
a "
                                     + toString(targetType));
                 }
-                return value;
+                return targetType.cast(value);
 
             // Convert --> Type
             } else {
@@ -158,7 +171,7 @@ public abstract class AbstractConverter 
                     log().debug("    Converted to " + toString(targetType) +
                                    " value '" + result + "'");
                 }
-                return result;
+                return targetType.cast(result);
             }
         } catch (Throwable t) {
             return handleError(targetType, value, t);
@@ -194,7 +207,7 @@ public abstract class AbstractConverter 
      * @return The converted value.
      * @throws Throwable if an error occurs converting to the specified type
      */
-    protected abstract Object convertToType(Class type, Object value) throws 
Throwable;
+    protected abstract <T> T convertToType(Class<T> type, Object value) throws 
Throwable;
 
     /**
      * Return the first element from an Array (or Collection)
@@ -218,7 +231,7 @@ public abstract class AbstractConverter 
             }
         }
         if (value instanceof Collection) {
-            Collection collection = (Collection)value;
+            Collection<?> collection = (Collection<?>)value;
             if (collection.size() > 0) {
                 return collection.iterator().next();
             } else {
@@ -241,7 +254,7 @@ public abstract class AbstractConverter 
      * @throws ConversionException if no default value has been
      * specified for this {@link Converter}.
      */
-    protected Object handleError(Class type, Object value, Throwable cause) {
+    protected <T> T handleError(Class<T> type, Object value, Throwable cause) {
         if (log().isDebugEnabled()) {
             if (cause instanceof ConversionException) {
                 log().debug("    Conversion threw ConversionException: " + 
cause.getMessage());
@@ -279,15 +292,16 @@ public abstract class AbstractConverter 
     /**
      * Handle missing values.
      * <p>
-     * If a default value has been specified then it is returned
-     * otherwise a ConversionException is thrown.
+     * If a default value has been specified, then it is returned (after a cast
+     * to the desired target class); otherwise a ConversionException is thrown.
      *
+     * @param <T> the desired target type
      * @param type Data type to which this value should be converted.
      * @return The default value.
      * @throws ConversionException if no default value has been
      * specified for this {@link Converter}.
      */
-    protected Object handleMissing(Class type) {
+    protected <T> T handleMissing(Class<T> type) {
 
         if (useDefault || type.equals(String.class)) {
             Object value = getDefault(type);
@@ -295,8 +309,8 @@ public abstract class AbstractConverter 
                 try {
                     value = convertToType(type, defaultValue);
                 } catch (Throwable t) {
-                    log().error("    Default conversion to " + toString(type)
-                            + "failed: " + t);
+                    throw new ConversionException("Default conversion to " + 
toString(type)
+                            + " failed.", t);
                 }
             }
             if (log().isDebugEnabled()) {
@@ -304,7 +318,8 @@ public abstract class AbstractConverter 
                         + (value == null ? "" : toString(value.getClass()) + " 
")
                         + "value '" + defaultValue + "'");
             }
-            return value;
+            // value is now either null or of the desired target type
+            return type.cast(value);
         }
 
         ConversionException cex =  new ConversionException("No value specified 
for '" +
@@ -348,7 +363,7 @@ public abstract class AbstractConverter 
      *
      * @return The default type this <code>Converter</code> handles.
      */
-    protected abstract Class getDefaultType();
+    protected abstract Class<? extends D> getDefaultType();
 
     /**
      * Return the default value for conversions to the specified
@@ -356,10 +371,10 @@ public abstract class AbstractConverter 
      * @param type Data type to which this value should be converted.
      * @return The default value for the specified type.
      */
-    protected Object getDefault(Class type) {
+    protected Object getDefault(Class<?> type) {
         if (type.equals(String.class)) {
             return null;
-        } else {
+        } else  {
             return defaultValue;
         }
     }
@@ -394,31 +409,34 @@ public abstract class AbstractConverter 
     }
 
     /**
-     * Change primitve Class types to the associated wrapper class.
+     * Change primitive Class types to the associated wrapper class.
      * @param type The class type to check.
      * @return The converted type.
      */
-     Class primitive(Class type) {
+    // All type casts are safe because the TYPE members of the wrapper types
+    // return their own class.
+    @SuppressWarnings("unchecked")
+    <T> Class<T> primitive(Class<T> type) {
         if (type == null || !type.isPrimitive()) {
             return type;
         }
 
         if (type == Integer.TYPE) {
-            return Integer.class;
+            return (Class<T>) Integer.class;
         } else if (type == Double.TYPE) {
-            return Double.class;
+            return (Class<T>) Double.class;
         } else if (type == Long.TYPE) {
-            return Long.class;
+            return (Class<T>) Long.class;
         } else if (type == Boolean.TYPE) {
-            return Boolean.class;
+            return (Class<T>) Boolean.class;
         } else if (type == Float.TYPE) {
-            return Float.class;
+            return (Class<T>) Float.class;
         } else if (type == Short.TYPE) {
-            return Short.class;
+            return (Class<T>) Short.class;
         } else if (type == Byte.TYPE) {
-            return Byte.class;
+            return (Class<T>) Byte.class;
         } else if (type == Character.TYPE) {
-            return Character.class;
+            return (Class<T>) Character.class;
         } else {
             return type;
         }
@@ -429,12 +447,12 @@ public abstract class AbstractConverter 
      * @param type The <code>java.lang.Class</code>.
      * @return The String representation.
      */
-    String toString(Class type) {
+    String toString(Class<?> type) {
         String typeName = null;
         if (type == null) {
             typeName = "null";
         } else if (type.isArray()) {
-            Class elementType = type.getComponentType();
+            Class<?> elementType = type.getComponentType();
             int count = 1;
             while (elementType.isArray()) {
                 elementType = elementType .getComponentType();
@@ -456,4 +474,19 @@ public abstract class AbstractConverter 
         }
         return typeName;
     }
+
+    /**
+     * Performs a conversion to the default type. This method is called if we 
do
+     * not have a target class. In this case, the T parameter is not set.
+     * Therefore, we can cast to it (which is required to fulfill the contract
+     * of the method signature).
+     *
+     * @param value the value to be converted
+     * @return the converted value
+     */
+    private <T> T convertToDefaultType(Object value) {
+        @SuppressWarnings("unchecked")
+        T result = (T) convert(getDefaultType(), value);
+        return result;
+    }
 }


Reply via email to