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;
+ }
}