improved null handling and javadoc

This commit is contained in:
Keith Donald
2011-06-05 17:41:08 +00:00
parent 0adcb2ad2e
commit 5f8faa3ae7
5 changed files with 107 additions and 15 deletions

View File

@@ -30,6 +30,7 @@ public interface ConversionService {
* @param sourceType the source type to convert from (required)
* @param targetType the target type to convert to (required)
* @return true if a conversion can be performed, false if not
* @throws IllegalArgumentException if targetType is null
*/
boolean canConvert(Class<?> sourceType, Class<?> targetType);
@@ -39,6 +40,7 @@ public interface ConversionService {
* @param targetType the target type to convert to (required)
* @return the converted object, an instance of targetType
* @throws ConversionException if an exception occurred
* @throws IllegalArgumentException if targetType is null
*/
<T> T convert(Object source, Class<T> targetType);
@@ -49,6 +51,8 @@ public interface ConversionService {
* @param sourceType context about the source type to convert from (required)
* @param targetType context about the target type to convert to (required)
* @return true if a conversion can be performed between the source and target types, false if not
* @throws IllegalArgumentException if targetType is null
* @see TypeDescriptor#forObject(Object)
*/
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
@@ -57,10 +61,13 @@ public interface ConversionService {
* The TypeDescriptors provide additional context about the field locations where conversion will occur, often object property locations.
* This flavor of the convert operation exists mainly for use by a general purpose data mapping framework, and not for use by user code.
* @param source the source object to convert (may be null)
* @param sourceType context about the source type converting from (required)
* @param sourceType context about the source type converting from (may be null if source is null)
* @param targetType context about the target type to convert to (required)
* @return the converted object, an instance of {@link TypeDescriptor#getObjectType() targetType}</code>
* @throws ConversionException if an exception occurred
* @throws IllegalArgumentException if targetType is null
* @throws IllegalArgumentException if sourceType is null but source is not null
* @see TypeDescriptor#forObject(Object)
*/
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);

View File

@@ -144,10 +144,12 @@ public class TypeDescriptor {
* If the methodParameter is a List<List<String>> and the nestingLevel is 2, the nested type descriptor will also be a String.class.
* If the methodParameter is a Map<Integer, String> and the nesting level is 1, the nested type descriptor will be String, derived from the map value.
* If the methodParameter is a List<Map<Integer, String>> and the nesting level is 2, the nested type descriptor will be String, derived from the map value.
* Returns null if a nested type cannot be obtained because it was not declared.
* For example, if the method parameter is a List&lt;?&gt;, the nested type descriptor returned will be null.
* @param methodParameter the method parameter with a nestingLevel of 1
* @param nestingLevel the nesting level of the collection/array element or map key/value declaration within the method parameter.
* @return the nested type descriptor
* @throws IllegalArgumentException if the method parameter is not of a collection, array, or map type.
* @return the nested type descriptor at the specified nesting level, or null if it could not be obtained.
* @throws IllegalArgumentException if the types up to the specified nesting level are not of collection, array, or map types.
*/
public static TypeDescriptor nested(MethodParameter methodParameter, int nestingLevel) {
return nested(new ParameterDescriptor(methodParameter), nestingLevel);
@@ -159,10 +161,12 @@ public class TypeDescriptor {
* If the field is a List<List<String>> and the nestingLevel is 2, the nested type descriptor will also be a String.class.
* If the field is a Map<Integer, String> and the nestingLevel is 1, the nested type descriptor will be String, derived from the map value.
* If the field is a List<Map<Integer, String>> and the nestingLevel is 2, the nested type descriptor will be String, derived from the map value.
* Returns null if a nested type cannot be obtained because it was not declared.
* For example, if the field is a List&lt;?&gt;, the nested type descriptor returned will be null.
* @param field the field
* @param nestingLevel the nesting level of the collection/array element or map key/value declaration within the field.
* @return the nested type descriptor
* @throws IllegalArgumentException if the field is not of a collection, array, or map type.
* @return the nested type descriptor at the specified nestingLevel, or null if it could not be obtained
* @throws IllegalArgumentException if the types up to the specified nesting level are not of collection, array, or map types.
*/
public static TypeDescriptor nested(Field field, int nestingLevel) {
return nested(new FieldDescriptor(field), nestingLevel);
@@ -174,10 +178,12 @@ public class TypeDescriptor {
* If the property is a List<List<String>> and the nestingLevel is 2, the nested type descriptor will also be a String.class.
* If the field is a Map<Integer, String> and the nestingLevel is 1, the nested type descriptor will be String, derived from the map value.
* If the property is a List<Map<Integer, String>> and the nestingLevel is 2, the nested type descriptor will be String, derived from the map value.
* Returns null if a nested type cannot be obtained because it was not declared.
* For example, if the property is a List&lt;?&gt;, the nested type descriptor returned will be null.
* @param property the property
* @param nestingLevel the nesting level of the collection/array element or map key/value declaration within the property.
* @return the nested type descriptor
* @throws IllegalArgumentException if the property is not of a collection, array, or map type.
* @return the nested type descriptor at the specified nestingLevel, or null if it could not be obtained
* @throws IllegalArgumentException if the types up to the specified nesting level are not of collection, array, or map types.
*/
public static TypeDescriptor nested(Property property, int nestingLevel) {
return nested(new BeanPropertyDescriptor(property), nestingLevel);

View File

@@ -133,7 +133,10 @@ public class GenericConversionService implements ConfigurableConversionService {
// implementing ConversionService
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
return canConvert(TypeDescriptor.valueOf(sourceType), TypeDescriptor.valueOf(targetType));
if (targetType == null) {
throw new IllegalArgumentException("The targetType to convert to cannot be null");
}
return canConvert(sourceType != null ? TypeDescriptor.valueOf(sourceType) : null, TypeDescriptor.valueOf(targetType));
}
@SuppressWarnings("unchecked")
@@ -145,6 +148,12 @@ public class GenericConversionService implements ConfigurableConversionService {
}
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
if (targetType == null) {
throw new IllegalArgumentException("The targetType to convert to cannot be null");
}
if (sourceType == null) {
return true;
}
if (logger.isTraceEnabled()) {
logger.trace("Checking if I can convert " + sourceType + " to " + targetType);
}

View File

@@ -50,6 +50,43 @@ public class GenericConversionServiceTests {
private GenericConversionService conversionService = new GenericConversionService();
@Test
public void canConvert() {
assertFalse(conversionService.canConvert(String.class, Integer.class));
conversionService.addConverterFactory(new StringToNumberConverterFactory());
assertTrue(conversionService.canConvert(String.class, Integer.class));
}
@Test
public void canConvertAssignable() {
assertTrue(conversionService.canConvert(String.class, String.class));
assertTrue(conversionService.canConvert(Integer.class, Number.class));
assertTrue(conversionService.canConvert(boolean.class, boolean.class));
assertTrue(conversionService.canConvert(boolean.class, Boolean.class));
}
@Test
public void canConvertIllegalArgumentNullTargetType() {
try {
assertFalse(conversionService.canConvert(String.class, null));
fail("Should have failed");
} catch (IllegalArgumentException e) {
}
try {
assertFalse(conversionService.canConvert(TypeDescriptor.valueOf(String.class), null));
fail("Should have failed");
} catch (IllegalArgumentException e) {
}
}
@Test
public void canConvertNullSourceType() {
assertTrue(conversionService.canConvert(null, Integer.class));
assertTrue(conversionService.canConvert(null, TypeDescriptor.valueOf(Integer.class)));
}
@Test
public void convert() {
conversionService.addConverterFactory(new StringToNumberConverterFactory());