diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/AbstractLineTokenizer.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/AbstractLineTokenizer.java index fea100733..08f75f55c 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/AbstractLineTokenizer.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/AbstractLineTokenizer.java @@ -19,11 +19,10 @@ package org.springframework.batch.item.file.transform; import java.util.ArrayList; import java.util.List; - - /** - * Abstract class handling common concerns of various {@link LineTokenizer} implementations - * such as dealing with names and actual construction of {@link FieldSet} + * Abstract class handling common concerns of various {@link LineTokenizer} + * implementations such as dealing with names and actual construction of + * {@link FieldSet} * * @author Dave Syer * @author Robert Kasanicky @@ -33,6 +32,18 @@ public abstract class AbstractLineTokenizer implements LineTokenizer { protected String[] names = new String[0]; + private FieldSetFactory fieldSetFactory = new DefaultFieldSetFactory(); + + /** + * Factory for {@link FieldSet} instances. Can be injected by clients to + * customize the default number and date formats. + * + * @param fieldSetFactory the {@link FieldSetFactory} to set + */ + public void setFieldSetFactory(FieldSetFactory fieldSetFactory) { + this.fieldSetFactory = fieldSetFactory; + } + /** * Setter for column names. Optional, but if set, then all lines must have * as many or fewer tokens. @@ -42,7 +53,7 @@ public abstract class AbstractLineTokenizer implements LineTokenizer { public void setNames(String[] names) { this.names = names; } - + /** * @return true if column names have been specified * @see #setNames(String[]) @@ -63,24 +74,24 @@ public abstract class AbstractLineTokenizer implements LineTokenizer { * @return the resulting tokens */ public FieldSet tokenize(String line) { - - if(line == null){ + + if (line == null) { line = ""; } List tokens = new ArrayList(doTokenize(line)); String[] values = (String[]) tokens.toArray(new String[tokens.size()]); - - if (names.length==0) { - return new DefaultFieldSet(values); + + if (names.length == 0) { + return fieldSetFactory.create(values); } - else if(values.length != names.length){ + else if (values.length != names.length) { throw new IncorrectTokenCountException(names.length, values.length); } - return new DefaultFieldSet(values, names); + return fieldSetFactory.create(values, names); } - + protected abstract List doTokenize(String line); } diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/DefaultFieldSet.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/DefaultFieldSet.java index bdf80f96d..d9396b9e8 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/DefaultFieldSet.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/DefaultFieldSet.java @@ -17,6 +17,8 @@ package org.springframework.batch.item.file.transform; import java.math.BigDecimal; +import java.text.DateFormat; +import java.text.NumberFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Arrays; @@ -35,10 +37,21 @@ import org.springframework.util.StringUtils; * @author Rob Harrop * @author Dave Syer */ +/** + * @author dsyer + * + */ public class DefaultFieldSet implements FieldSet { private final static String DEFAULT_DATE_PATTERN = "yyyy-MM-dd"; + private DateFormat dateFormat = new SimpleDateFormat(DEFAULT_DATE_PATTERN); + { + dateFormat.setLenient(false); + } + + private NumberFormat numberFormat = NumberFormat.getInstance(); + /** * The fields wrapped by this 'FieldSet' instance. */ @@ -46,6 +59,24 @@ public class DefaultFieldSet implements FieldSet { private List names; + /** + * The {@link NumberFormat} to use for parsing numbers. If unset the default + * locale will be used. + * @param numberFormat the {@link NumberFormat} to use for number parsing + */ + public void setNumberFormat(NumberFormat numberFormat) { + this.numberFormat = numberFormat; + } + + /** + * The {@link DateFormat} to use for parsing numbers. If unset the default + * pattern is ISO standard yyyy/MM/dd. + * @param dateFormat the {@link DateFormat} to use for date parsing + */ + public void setDateFormat(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + public DefaultFieldSet(String[] tokens) { this.tokens = tokens == null ? null : (String[]) tokens.clone(); } @@ -60,9 +91,10 @@ public class DefaultFieldSet implements FieldSet { this.tokens = (String[]) tokens.clone(); this.names = Arrays.asList(names); } - + /* * (non-Javadoc) + * * @see org.springframework.batch.item.file.mapping.IFieldSet#getNames() */ public String[] getNames() { @@ -71,16 +103,19 @@ public class DefaultFieldSet implements FieldSet { } return names.toArray(new String[names.size()]); } - - /* (non-Javadoc) + + /* + * (non-Javadoc) + * * @see org.springframework.batch.item.file.mapping.FieldSet#hasNames() */ public boolean hasNames() { - return names!=null; + return names != null; } /* * (non-Javadoc) + * * @see org.springframework.batch.item.file.mapping.IFieldSet#getValues() */ public String[] getValues() { @@ -89,7 +124,9 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readString(int) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readString(int) */ public String readString(int index) { return readAndTrim(index); @@ -97,23 +134,31 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readString(java.lang.String) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readString(java + * .lang.String) */ public String readString(String name) { return readString(indexOf(name)); } - + /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readRawString(int) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readRawString(int) */ public String readRawString(int index) { return tokens[index]; } - + /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readRawString(java.lang.String) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readRawString(java + * .lang.String) */ public String readRawString(String name) { return readRawString(indexOf(name)); @@ -121,7 +166,9 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readBoolean(int) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readBoolean(int) */ public boolean readBoolean(int index) { return readBoolean(index, "true"); @@ -129,7 +176,10 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readBoolean(java.lang.String) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readBoolean(java + * .lang.String) */ public boolean readBoolean(String name) { return readBoolean(indexOf(name)); @@ -137,7 +187,9 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readBoolean(int, + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readBoolean(int, * java.lang.String) */ public boolean readBoolean(int index, String trueValue) { @@ -150,8 +202,10 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readBoolean(java.lang.String, - * java.lang.String) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readBoolean(java + * .lang.String, java.lang.String) */ public boolean readBoolean(String name, String trueValue) { return readBoolean(indexOf(name), trueValue); @@ -159,6 +213,7 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) + * * @see org.springframework.batch.item.file.mapping.IFieldSet#readChar(int) */ public char readChar(int index) { @@ -171,7 +226,10 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readChar(java.lang.String) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readChar(java.lang + * .String) */ public char readChar(String name) { return readChar(indexOf(name)); @@ -179,6 +237,7 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) + * * @see org.springframework.batch.item.file.mapping.IFieldSet#readByte(int) */ public byte readByte(int index) { @@ -187,7 +246,10 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readByte(java.lang.String) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readByte(java.lang + * .String) */ public byte readByte(String name) { return readByte(indexOf(name)); @@ -195,6 +257,7 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) + * * @see org.springframework.batch.item.file.mapping.IFieldSet#readShort(int) */ public short readShort(int index) { @@ -203,7 +266,10 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readShort(java.lang.String) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readShort(java. + * lang.String) */ public short readShort(String name) { return readShort(indexOf(name)); @@ -211,15 +277,19 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) + * * @see org.springframework.batch.item.file.mapping.IFieldSet#readInt(int) */ public int readInt(int index) { - return Integer.parseInt(readAndTrim(index)); + return parseNumber(readAndTrim(index)).intValue(); } /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readInt(java.lang.String) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readInt(java.lang + * .String) */ public int readInt(String name) { return readInt(indexOf(name)); @@ -227,6 +297,7 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) + * * @see org.springframework.batch.item.file.mapping.IFieldSet#readInt(int, * int) */ @@ -238,8 +309,10 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readInt(java.lang.String, - * int) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readInt(java.lang + * .String, int) */ public int readInt(String name, int defaultValue) { return readInt(indexOf(name), defaultValue); @@ -247,15 +320,19 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) + * * @see org.springframework.batch.item.file.mapping.IFieldSet#readLong(int) */ public long readLong(int index) { - return Long.parseLong(readAndTrim(index)); + return (Long) parseNumber(readAndTrim(index)); } /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readLong(java.lang.String) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readLong(java.lang + * .String) */ public long readLong(String name) { return readLong(indexOf(name)); @@ -263,6 +340,7 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) + * * @see org.springframework.batch.item.file.mapping.IFieldSet#readLong(int, * long) */ @@ -274,8 +352,10 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readLong(java.lang.String, - * long) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readLong(java.lang + * .String, long) */ public long readLong(String name, long defaultValue) { return readLong(indexOf(name), defaultValue); @@ -283,15 +363,19 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) + * * @see org.springframework.batch.item.file.mapping.IFieldSet#readFloat(int) */ public float readFloat(int index) { - return Float.parseFloat(readAndTrim(index)); + return parseNumber(readAndTrim(index)).floatValue(); } /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readFloat(java.lang.String) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readFloat(java. + * lang.String) */ public float readFloat(String name) { return readFloat(indexOf(name)); @@ -299,15 +383,20 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readDouble(int) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readDouble(int) */ public double readDouble(int index) { - return Double.parseDouble(readAndTrim(index)); + return (Double) parseNumber(readAndTrim(index)); } /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readDouble(java.lang.String) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readDouble(java + * .lang.String) */ public double readDouble(String name) { return readDouble(indexOf(name)); @@ -315,7 +404,9 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readBigDecimal(int) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readBigDecimal(int) */ public BigDecimal readBigDecimal(int index) { return readBigDecimal(index, null); @@ -323,7 +414,10 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readBigDecimal(java.lang.String) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readBigDecimal( + * java.lang.String) */ public BigDecimal readBigDecimal(String name) { return readBigDecimal(name, null); @@ -331,7 +425,9 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readBigDecimal(int, + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readBigDecimal(int, * java.math.BigDecimal) */ public BigDecimal readBigDecimal(int index, BigDecimal defaultValue) { @@ -347,8 +443,10 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readBigDecimal(java.lang.String, - * java.math.BigDecimal) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readBigDecimal( + * java.lang.String, java.math.BigDecimal) */ public BigDecimal readBigDecimal(String name, BigDecimal defaultValue) { try { @@ -361,43 +459,47 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) + * * @see org.springframework.batch.item.file.mapping.IFieldSet#readDate(int) */ public Date readDate(int index) { - return readDate(index, DEFAULT_DATE_PATTERN); + return parseDate(readAndTrim(index), dateFormat); } /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readDate(java.lang.String) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readDate(java.lang + * .String) */ public Date readDate(String name) { - return readDate(name, DEFAULT_DATE_PATTERN); + try { + return readDate(indexOf(name)); + } + catch (IllegalArgumentException e) { + throw new IllegalArgumentException(e.getMessage() + ", name: [" + name + "]"); + } } /* * (non-Javadoc) + * * @see org.springframework.batch.item.file.mapping.IFieldSet#readDate(int, * java.lang.String) */ public Date readDate(int index, String pattern) { SimpleDateFormat sdf = new SimpleDateFormat(pattern); sdf.setLenient(false); - Date date; - String value = readAndTrim(index); - try { - date = sdf.parse(value); - } - catch (ParseException e) { - throw new IllegalArgumentException(e.getMessage() + ", pattern: [" + pattern + "]"); - } - return date; + return parseDate(readAndTrim(index), sdf); } /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#readDate(java.lang.String, - * java.lang.String) + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#readDate(java.lang + * .String, java.lang.String) */ public Date readDate(String name, String pattern) { try { @@ -410,7 +512,9 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#getFieldCount() + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#getFieldCount() */ public int getFieldCount() { return tokens.length; @@ -433,7 +537,8 @@ public class DefaultFieldSet implements FieldSet { } /** - * Read and trim the {@link String} value from column with given 'name. + * Read and trim the {@link String} value from column with given ' + * name. * * @throws IllegalArgumentException if a column with given name is not * defined. @@ -492,7 +597,9 @@ public class DefaultFieldSet implements FieldSet { /* * (non-Javadoc) - * @see org.springframework.batch.item.file.mapping.IFieldSet#getProperties() + * + * @see + * org.springframework.batch.item.file.mapping.IFieldSet#getProperties() */ public Properties getProperties() { if (names == null) { @@ -508,4 +615,29 @@ public class DefaultFieldSet implements FieldSet { return props; } + private Number parseNumber(String candidate) { + try { + return numberFormat.parse(candidate); + } + catch (ParseException e) { + throw new NumberFormatException("Unparseable number: " + candidate); + } + } + + private Date parseDate(String readAndTrim, DateFormat dateFormat) { + try { + return dateFormat.parse(readAndTrim); + } + catch (ParseException e) { + String pattern; + if (dateFormat instanceof SimpleDateFormat) { + pattern = ((SimpleDateFormat) dateFormat).toPattern(); + } else { + pattern = dateFormat.toString(); + } + throw new IllegalArgumentException(e.getMessage() + ", format: [" + pattern + "]"); + } + } + + } diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/DefaultFieldSetFactory.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/DefaultFieldSetFactory.java new file mode 100644 index 000000000..3074cbf5a --- /dev/null +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/DefaultFieldSetFactory.java @@ -0,0 +1,64 @@ +package org.springframework.batch.item.file.transform; + +import java.text.DateFormat; +import java.text.NumberFormat; + +/** + * Default implementation of {@link FieldSetFactory} with no special knowledge + * of the {@link FieldSet} required. Returns a {@link DefaultFieldSet} from both + * factory methods. + * + * @author Dave Syer + * + */ +public class DefaultFieldSetFactory implements FieldSetFactory { + + private DateFormat dateFormat; + + private NumberFormat numberFormat; + + /** + * The {@link NumberFormat} to use for parsing numbers. If unset the default + * locale will be used. + * @param numberFormat the {@link NumberFormat} to use for number parsing + */ + public void setNumberFormat(NumberFormat numberFormat) { + this.numberFormat = numberFormat; + } + + /** + * The {@link DateFormat} to use for parsing numbers. If unset the default + * pattern is ISO standard yyyy/MM/dd. + * @param dateFormat the {@link DateFormat} to use for date parsing + */ + public void setDateFormat(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + /** + * {@inheritDoc} + */ + public FieldSet create(String[] values, String[] names) { + DefaultFieldSet fieldSet = new DefaultFieldSet(values, names); + return enhance(fieldSet); + } + + /** + * {@inheritDoc} + */ + public FieldSet create(String[] values) { + DefaultFieldSet fieldSet = new DefaultFieldSet(values); + return enhance(fieldSet); + } + + private FieldSet enhance(DefaultFieldSet fieldSet) { + if (dateFormat!=null) { + fieldSet.setDateFormat(dateFormat); + } + if (numberFormat!=null) { + fieldSet.setDateFormat(dateFormat); + } + return fieldSet; + } + +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/FieldSetFactory.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/FieldSetFactory.java new file mode 100644 index 000000000..c547cff67 --- /dev/null +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/FieldSetFactory.java @@ -0,0 +1,18 @@ +/** + * + */ +package org.springframework.batch.item.file.transform; + +/** + * Factory interface for creating {@link FieldSet} instances. + * + * @author Dave Syer + * + */ +public interface FieldSetFactory { + + FieldSet create(String[] names, String[] values); + + FieldSet create(String[] values); + +} diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/mapping/PrefixMatchingCompositeLineMapperTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/mapping/PrefixMatchingCompositeLineMapperTests.java index 2b2b574cd..c4aaf51fa 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/mapping/PrefixMatchingCompositeLineMapperTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/mapping/PrefixMatchingCompositeLineMapperTests.java @@ -39,7 +39,7 @@ public class PrefixMatchingCompositeLineMapperTests { private PrefixMatchingCompositeLineMapper mapper = new PrefixMatchingCompositeLineMapper(); @Test(expected = IllegalArgumentException.class) - public void test_NoMappers() throws Exception { + public void testNoMappers() throws Exception { mapper.setTokenizers(Collections.singletonMap("", (LineTokenizer) new DelimitedLineTokenizer())); Map> fieldSetMappers = Collections.emptyMap(); mapper.setFieldSetMappers(fieldSetMappers); @@ -47,7 +47,7 @@ public class PrefixMatchingCompositeLineMapperTests { } @Test - public void test_KeyFound() throws Exception { + public void testKeyFound() throws Exception { Map tokenizers = new HashMap(); tokenizers.put("foo", new LineTokenizer() { public FieldSet tokenize(String line) { @@ -79,7 +79,7 @@ public class PrefixMatchingCompositeLineMapperTests { } @Test(expected = IllegalStateException.class) - public void test_MapperKeyNotFound() throws Exception { + public void testMapperKeyNotFound() throws Exception { Map tokenizers = new HashMap(); tokenizers.put("foo", new LineTokenizer() { public FieldSet tokenize(String line) { diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/transform/FieldSetTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/transform/FieldSetTests.java index e4d186b7c..04785831e 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/transform/FieldSetTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/transform/FieldSetTests.java @@ -16,23 +16,31 @@ package org.springframework.batch.item.file.transform; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.math.BigDecimal; +import java.text.NumberFormat; import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Locale; -import junit.framework.TestCase; +import org.junit.Before; +import org.junit.Test; -import org.springframework.batch.item.file.transform.DefaultFieldSet; -import org.springframework.batch.item.file.transform.FieldSet; +public class FieldSetTests { -public class FieldSetTests extends TestCase { - FieldSet fieldSet; + DefaultFieldSet fieldSet; String[] tokens; String[] names; - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { tokens = new String[] { "TestString", "true", "C", "10", "-472", "354224", "543", "124.3", "424.3", "324", null, "2007-10-12", "12-10-2007", "" }; @@ -44,11 +52,13 @@ public class FieldSetTests extends TestCase { } + @Test public void testNames() throws Exception { assertTrue(fieldSet.hasNames()); assertEquals(fieldSet.getFieldCount(), fieldSet.getNames().length); } + @Test public void testNamesNotKnown() throws Exception { fieldSet = new DefaultFieldSet(new String[] { "foo" }); assertFalse(fieldSet.hasNames()); @@ -61,6 +71,7 @@ public class FieldSetTests extends TestCase { } } + @Test public void testReadString() throws ParseException { assertEquals(fieldSet.readString(0), "TestString"); @@ -68,6 +79,7 @@ public class FieldSetTests extends TestCase { } + @Test public void testReadChar() throws Exception { assertTrue(fieldSet.readChar(2) == 'C'); @@ -75,6 +87,7 @@ public class FieldSetTests extends TestCase { } + @Test public void testReadBooleanTrue() throws Exception { assertTrue(fieldSet.readBoolean(1)); @@ -82,6 +95,7 @@ public class FieldSetTests extends TestCase { } + @Test public void testReadByte() throws Exception { assertTrue(fieldSet.readByte(3) == 10); @@ -89,6 +103,7 @@ public class FieldSetTests extends TestCase { } + @Test public void testReadShort() throws Exception { assertTrue(fieldSet.readShort(4) == -472); @@ -96,6 +111,7 @@ public class FieldSetTests extends TestCase { } + @Test public void testReadFloat() throws Exception { assertTrue(fieldSet.readFloat(7) == 124.3F); @@ -103,6 +119,7 @@ public class FieldSetTests extends TestCase { } + @Test public void testReadDouble() throws Exception { assertTrue(fieldSet.readDouble(8) == 424.3); @@ -110,6 +127,7 @@ public class FieldSetTests extends TestCase { } + @Test public void testReadBigDecimal() throws Exception { BigDecimal bd = new BigDecimal(324); @@ -118,6 +136,7 @@ public class FieldSetTests extends TestCase { } + @Test public void testReadBigDecimalWithDefaultvalue() throws Exception { BigDecimal bd = new BigDecimal(324); @@ -126,6 +145,7 @@ public class FieldSetTests extends TestCase { } + @Test public void testReadNonExistentField() throws Exception { try { @@ -138,6 +158,7 @@ public class FieldSetTests extends TestCase { } + @Test public void testReadIndexOutOfRange() throws Exception { try { @@ -157,6 +178,7 @@ public class FieldSetTests extends TestCase { } } + @Test public void testReadBooleanWithTrueValue() { assertTrue(fieldSet.readBoolean(1, "true")); assertFalse(fieldSet.readBoolean(1, "incorrect trueValue")); @@ -165,11 +187,13 @@ public class FieldSetTests extends TestCase { assertFalse(fieldSet.readBoolean("Boolean", "incorrect trueValue")); } + @Test public void testReadBooleanFalse() { fieldSet = new DefaultFieldSet(new String[] { "false" }); assertFalse(fieldSet.readBoolean(0)); } + @Test public void testReadCharException() { try { fieldSet.readChar(1); @@ -188,11 +212,26 @@ public class FieldSetTests extends TestCase { } } + @Test public void testReadInt() throws Exception { assertEquals(354224, fieldSet.readInt(5)); assertEquals(354224, fieldSet.readInt("Integer")); } + @Test + public void testReadIntWithSeparator() throws Exception { + fieldSet = new DefaultFieldSet(new String[] {"354,224"}); + assertEquals(354224, fieldSet.readInt(0)); + } + + @Test + public void testReadIntWithSeparatorAndFormat() throws Exception { + fieldSet = new DefaultFieldSet(new String[] {"354.224"}); + fieldSet.setNumberFormat(NumberFormat.getInstance(Locale.GERMAN)); + assertEquals(354224, fieldSet.readInt(0)); + } + + @Test public void testReadBlankInt() { // Trying to parse a blank field as an integer, but without a default @@ -215,26 +254,31 @@ public class FieldSetTests extends TestCase { } + @Test public void testReadLong() throws Exception { assertEquals(543, fieldSet.readLong(6)); assertEquals(543, fieldSet.readLong("Long")); } + @Test public void testReadLongWithPadding() throws Exception { fieldSet = new DefaultFieldSet(new String[] { "000009" }); assertEquals(9, fieldSet.readLong(0)); } + @Test public void testReadIntWithNullValue() { assertEquals(5, fieldSet.readInt(10, 5)); assertEquals(5, fieldSet.readInt("Null", 5)); } + @Test public void testReadIntWithDefaultAndNotNull() throws Exception { assertEquals(354224, fieldSet.readInt(5, 5)); assertEquals(354224, fieldSet.readInt("Integer", 5)); } + @Test public void testReadLongWithNullValue() { int defaultValue = 5; int indexOfNull = 10; @@ -250,6 +294,7 @@ public class FieldSetTests extends TestCase { assertEquals(fieldSet.readLong(nameNotNull, defaultValue), longValueAtIndex); } + @Test public void testReadBigDecimalInvalid() { int index = 0; @@ -263,6 +308,7 @@ public class FieldSetTests extends TestCase { } + @Test public void testReadBigDecimalByNameInvalid() throws Exception { try { fieldSet.readBigDecimal("String"); @@ -274,11 +320,21 @@ public class FieldSetTests extends TestCase { } } + @Test public void testReadDate() throws Exception { assertNotNull(fieldSet.readDate(11)); assertNotNull(fieldSet.readDate("Date")); } + @Test + public void testReadDateWithFormat() throws Exception { + fieldSet = new DefaultFieldSet(new String[] {"13/01/1999"}); + SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy"); + fieldSet.setDateFormat(dateFormat); + assertEquals(dateFormat.parse("13/01/1999"), fieldSet.readDate(0)); + } + + @Test public void testReadDateInvalid() throws Exception { try { @@ -291,6 +347,7 @@ public class FieldSetTests extends TestCase { } + @Test public void testReadDateInvalidByName() throws Exception { try { @@ -303,6 +360,7 @@ public class FieldSetTests extends TestCase { } + @Test public void testReadDateInvalidWithPattern() throws Exception { try { @@ -314,6 +372,7 @@ public class FieldSetTests extends TestCase { } } + @Test public void testStrictReadDateWithPattern() throws Exception { fieldSet = new DefaultFieldSet(new String[] {"50-2-13"}); @@ -327,6 +386,7 @@ public class FieldSetTests extends TestCase { } } + @Test public void testStrictReadDateWithPatternAndStrangeDate() throws Exception { fieldSet = new DefaultFieldSet(new String[] {"5550212"}); @@ -340,6 +400,7 @@ public class FieldSetTests extends TestCase { } } + @Test public void testReadDateByNameInvalidWithPattern() throws Exception { try { @@ -352,6 +413,7 @@ public class FieldSetTests extends TestCase { } } + @Test public void testEquals() { assertEquals(fieldSet, fieldSet); @@ -364,18 +426,22 @@ public class FieldSetTests extends TestCase { assertEquals(fs1, fs2); } + @Test public void testNullField() { assertEquals(null, fieldSet.readString(10)); } + @Test public void testEqualsNull() { assertFalse(fieldSet.equals(null)); } + @Test public void testEqualsNullTokens() { assertFalse(new DefaultFieldSet(null).equals(fieldSet)); } + @Test public void testEqualsNotEqual() throws Exception { String[] tokens1 = new String[] { "token1" }; @@ -386,14 +452,17 @@ public class FieldSetTests extends TestCase { } + @Test public void testHashCode() throws Exception { assertEquals(fieldSet.hashCode(), new DefaultFieldSet(tokens).hashCode()); } + @Test public void testHashCodeWithNullTokens() throws Exception { assertEquals(0, new DefaultFieldSet(null).hashCode()); } + @Test public void testConstructor() throws Exception { try { new DefaultFieldSet(new String[] { "1", "2" }, new String[] { "a" }); @@ -404,26 +473,31 @@ public class FieldSetTests extends TestCase { } } + @Test public void testToStringWithNames() throws Exception { fieldSet = new DefaultFieldSet(new String[] { "foo", "bar" }, new String[] { "Foo", "Bar" }); assertTrue(fieldSet.toString().indexOf("Foo=foo") >= 0); } + @Test public void testToStringWithoutNames() throws Exception { fieldSet = new DefaultFieldSet(new String[] { "foo", "bar" }); assertTrue(fieldSet.toString().indexOf("foo") >= 0); } + @Test public void testToStringNullTokens() throws Exception { fieldSet = new DefaultFieldSet(null); assertEquals("", fieldSet.toString()); } + @Test public void testProperties() throws Exception { assertEquals("foo", new DefaultFieldSet(new String[] { "foo", "bar" }, new String[] { "Foo", "Bar" }) .getProperties().getProperty("Foo")); } + @Test public void testPropertiesWithNoNames() throws Exception { try { new DefaultFieldSet(new String[] { "foo", "bar" }).getProperties(); @@ -434,12 +508,14 @@ public class FieldSetTests extends TestCase { } } + @Test public void testPropertiesWithWhiteSpace() throws Exception { assertEquals("bar", new DefaultFieldSet(new String[] { "foo", "bar " }, new String[] { "Foo", "Bar" }) .getProperties().getProperty("Bar")); } + @Test public void testPropertiesWithNullValues() throws Exception { fieldSet = new DefaultFieldSet(new String[] { null, "bar" }, new String[] { "Foo", "Bar" }); @@ -447,6 +523,7 @@ public class FieldSetTests extends TestCase { assertEquals(null, fieldSet.getProperties().getProperty("Foo")); } + @Test public void testAccessByNameWhenNamesMissing() throws Exception { try { new DefaultFieldSet(new String[] { "1", "2" }).readInt("a"); @@ -457,6 +534,7 @@ public class FieldSetTests extends TestCase { } } + @Test public void testGetValues() { String[] values = fieldSet.getValues(); assertEquals(tokens.length, values.length); @@ -465,6 +543,7 @@ public class FieldSetTests extends TestCase { } } + @Test public void testPaddedLong() { FieldSet fs = new DefaultFieldSet(new String[] { "00000009" }); @@ -472,6 +551,7 @@ public class FieldSetTests extends TestCase { assertEquals(value, 9); } + @Test public void testReadRawString() { String name = "fieldName"; String value = " string with trailing whitespace ";