diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/converter/DefaultJobParametersConverter.java b/spring-batch-core/src/main/java/org/springframework/batch/core/converter/DefaultJobParametersConverter.java index 321dc53d6..be167adf7 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/converter/DefaultJobParametersConverter.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/converter/DefaultJobParametersConverter.java @@ -31,17 +31,18 @@ import org.springframework.batch.core.JobParametersBuilder; import org.springframework.util.StringUtils; /** - * Converter for {@link JobParameters} instances using a simple naming convention for property keys. Key names ending - * with "(<type>)" where type is one of string, date, long are converted to the corresponding type. The default - * type is string. E.g. + * Converter for {@link JobParameters} instances using a simple naming + * convention for property keys. Key names ending with "(<type>)" where + * type is one of string, date, long are converted to the corresponding type. + * The default type is string. E.g. * *
* schedule.date(date)=2007/12/11 * department.id(long)=2345 ** - * The literal values are converted to the correct type using the default Spring strategies, augmented if necessary by - * the custom editors provided. + * The literal values are converted to the correct type using the default Spring + * strategies, augmented if necessary by the custom editors provided. * * @author Dave Syer * @@ -54,15 +55,18 @@ public class DefaultJobParametersConverter implements JobParametersConverter { public static final String LONG_TYPE = "(long)"; + private static final String DOUBLE_TYPE = "(double)"; + private DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd"); private NumberFormat numberFormat = new DecimalFormat("#"); /** - * Check for suffix on keys and use those to decide how to convert the value. + * Check for suffix on keys and use those to decide how to convert the + * value. * - * @throws IllegalArgumentException if a number or date is passed in that cannot be parsed, or cast to the correct - * type. + * @throws IllegalArgumentException if a number or date is passed in that + * cannot be parsed, or cast to the correct type. * * @see org.springframework.batch.core.converter.JobParametersConverter#getJobParameters(java.util.Properties) */ @@ -82,28 +86,39 @@ public class DefaultJobParametersConverter implements JobParametersConverter { Date date; try { date = dateFormat.parse(value); - } catch (ParseException ex) { + } + catch (ParseException ex) { String suffix = (dateFormat instanceof SimpleDateFormat) ? ", use " - + ((SimpleDateFormat) dateFormat).toPattern() : ""; + + ((SimpleDateFormat) dateFormat).toPattern() : ""; throw new IllegalArgumentException("Date format is invalid: [" + value + "]" + suffix); } propertiesBuilder.addDate(StringUtils.replace(key, DATE_TYPE, ""), date); - } else if (key.endsWith(LONG_TYPE)) { + } + else if (key.endsWith(LONG_TYPE)) { Long result; try { - result = (Long) numberFormat.parse(value); - } catch (ParseException ex) { - String suffix = (numberFormat instanceof DecimalFormat) ? ", use " - + ((DecimalFormat) numberFormat).toPattern() : ""; - throw new IllegalArgumentException("Number format is invalid: [" + value + "], use " + suffix); - } catch (ClassCastException ex) { - throw new IllegalArgumentException("Number format is invalid: [" + value - + "], use a format with no decimal places"); + result = (Long) parseNumber(value); + } + catch (ClassCastException ex) { + throw new IllegalArgumentException("Number format is invalid for long value: [" + value + + "], use a format with no decimal places"); } propertiesBuilder.addLong(StringUtils.replace(key, LONG_TYPE, ""), result); - } else if (StringUtils.endsWithIgnoreCase(key, STRING_TYPE)) { + } + else if (key.endsWith(DOUBLE_TYPE)) { + Double result; + try { + result = (Double) parseNumber(value); + } + catch (ClassCastException ex) { + throw new IllegalArgumentException("Number format is invalid for double value: [" + value + "]"); + } + propertiesBuilder.addDouble(StringUtils.replace(key, DOUBLE_TYPE, ""), result); + } + else if (StringUtils.endsWithIgnoreCase(key, STRING_TYPE)) { propertiesBuilder.addString(StringUtils.replace(key, STRING_TYPE, ""), value); - } else { + } + else { propertiesBuilder.addString(key, value.toString()); } } @@ -112,7 +127,22 @@ public class DefaultJobParametersConverter implements JobParametersConverter { } /** - * Use the same suffixes to create properties (omitting the string suffix because it is the default). + * Delegate to {@link NumberFormat} to parse the value + */ + private Number parseNumber(String value) { + try { + return numberFormat.parse(value); + } + catch (ParseException ex) { + String suffix = (numberFormat instanceof DecimalFormat) ? ", use " + + ((DecimalFormat) numberFormat).toPattern() : ""; + throw new IllegalArgumentException("Number format is invalid: [" + value + "], use " + suffix); + } + } + + /** + * Use the same suffixes to create properties (omitting the string suffix + * because it is the default). * * @see org.springframework.batch.core.converter.JobParametersConverter#getProperties(org.springframework.batch.core.JobParameters) */ @@ -130,9 +160,11 @@ public class DefaultJobParametersConverter implements JobParametersConverter { Object value = entry.getValue(); if (value instanceof Date) { result.setProperty(key + DATE_TYPE, dateFormat.format(value)); - } else if (value instanceof Long) { + } + else if (value instanceof Long) { result.setProperty(key + LONG_TYPE, numberFormat.format(value)); - } else { + } + else { result.setProperty(key, "" + value); } } @@ -149,8 +181,8 @@ public class DefaultJobParametersConverter implements JobParametersConverter { } /** - * Public setter for the {@link NumberFormat}. Used to parse longs, so must not contain decimal place (e.g. use "#" - * or "#,###"). + * Public setter for the {@link NumberFormat}. Used to parse longs, so must + * not contain decimal place (e.g. use "#" or "#,###"). * * @param numberFormat the {@link NumberFormat} to set */ diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/converter/DefaultJobParametersConverterTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/converter/DefaultJobParametersConverterTests.java index 0df38d630..0890ae471 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/converter/DefaultJobParametersConverterTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/converter/DefaultJobParametersConverterTests.java @@ -101,7 +101,7 @@ public class DefaultJobParametersConverterTests extends TestCase { } } - public void testGetParametersWithDouble() throws Exception { + public void testGetParametersWithDoubleValueDeclaredAsLong() throws Exception { String[] args = new String[] { "value(long)=1.03" }; factory.setNumberFormat(new DecimalFormat("#.#")); @@ -114,6 +114,28 @@ public class DefaultJobParametersConverterTests extends TestCase { assertTrue("Message should contain 'decimal': " + message, contains(message, "decimal")); } } + + public void testGetParametersWithBogusDouble() throws Exception { + + String[] args = new String[] { "value(double)=foo" }; + + try { + factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "=")); + } catch (IllegalArgumentException e) { + String message = e.getMessage(); + assertTrue("Message should contain wrong number: " + message, contains(message, "foo")); + assertTrue("Message should contain format: " + message, contains(message, "#")); + } + } + + public void testGetParametersWithDouble() throws Exception { + + String[] args = new String[] { "value(double)=1.38" }; + + JobParameters props = factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "=")); + assertNotNull(props); + assertEquals(1.38, props.getDouble("value").doubleValue(), Double.MIN_VALUE); + } public void testGetProperties() throws Exception {