RESOLVED - issue BATCH-289: FieldSet should be an interface

http://jira.springframework.org/browse/BATCH-289

Created interface and moved implementation to DefaultFieldSet.
This commit is contained in:
dsyer
2008-01-16 14:39:11 +00:00
parent 5627d28945
commit 9c2df0b180
12 changed files with 550 additions and 708 deletions

View File

@@ -19,8 +19,9 @@ package org.springframework.batch.io.file;
import java.io.IOException;
import org.springframework.batch.io.exception.FlatFileParsingException;
import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.io.file.mapping.DefaultFieldSet;
import org.springframework.batch.io.file.mapping.FieldSetMapper;
import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.io.file.separator.LineReader;
import org.springframework.batch.io.file.separator.RecordSeparatorPolicy;
import org.springframework.batch.io.file.separator.ResourceLineReader;
@@ -37,7 +38,7 @@ import org.springframework.util.Assert;
/**
* This class represents a basic input source, that reads data from the file and
* returns it as structured tuples in the form of{@link FieldSet} instances.
* returns it as structured tuples in the form of{@link DefaultFieldSet} instances.
* The location of the file is defined by the resource property. To separate the
* structure of the file, {@link LineTokenizer} is used to parse data obtained
* from the file. <br/>

View File

@@ -44,15 +44,15 @@ import org.springframework.validation.ObjectError;
/**
* {@link FieldSetMapper} implementation based on bean property paths. The
* {@link FieldSet} to be mapped should have field name meta data corresponding
* {@link DefaultFieldSet} to be mapped should have field name meta data corresponding
* to bean property paths in a prototype instance of the desired type. The
* prototype instance is initialized either by referring to to object by bean
* name in the enclosing BeanFactory, or by providing a class to instantiate
* reflectively.<br/>
*
* Nested property paths, including indexed properties in maps and collections,
* can be referenced by the {@link FieldSet} names. They will be converted to
* nested bean properties inside the prototype. The {@link FieldSet} and the
* can be referenced by the {@link DefaultFieldSet} names. They will be converted to
* nested bean properties inside the prototype. The {@link DefaultFieldSet} and the
* prototype are thus tightly coupled by the fields that are available and those
* that can be initialized. If some of the nested properties are optional (e.g.
* collection members) they need to be removed by a post processor.<br/>
@@ -103,7 +103,7 @@ public class BeanWrapperFieldSetMapper implements FieldSetMapper, BeanFactoryAwa
/**
* The bean name (id) for an object that can be populated from the field set
* that will be passed into {@link #mapLine(FieldSet)}. Typically a
* that will be passed into {@link #mapLine(DefaultFieldSet)}. Typically a
* prototype scoped bean so that a new instance is returned for each field
* set mapped.
*
@@ -119,7 +119,7 @@ public class BeanWrapperFieldSetMapper implements FieldSetMapper, BeanFactoryAwa
/**
* Public setter for the type of bean to create instead of using a prototype
* bean. An object of this type will be created from its default constructor
* for every call to {@link #mapLine(FieldSet)}.<br/>
* for every call to {@link #mapLine(DefaultFieldSet)}.<br/>
*
* Either this property or the prototype bean name must be specified, but
* not both.
@@ -144,17 +144,17 @@ public class BeanWrapperFieldSetMapper implements FieldSetMapper, BeanFactoryAwa
}
/**
* Map the {@link FieldSet} to an object retrieved from the enclosing Spring
* Map the {@link DefaultFieldSet} to an object retrieved from the enclosing Spring
* context, or to a new instance of the required type if no prototype is
* available.
*
* @throws NotWritablePropertyException if the {@link FieldSet} contains a
* @throws NotWritablePropertyException if the {@link DefaultFieldSet} contains a
* field that cannot be mapped to a bean property.
* @throws BindingException if there is a type conversion or other error (if
* the {@link DataBinder} from {@link #createBinder(Object)} has errors
* after binding).
*
* @see org.springframework.batch.io.file.mapping.FieldSetMapper#mapLine(org.springframework.batch.io.file.mapping.FieldSet)
* @see org.springframework.batch.io.file.mapping.FieldSetMapper#mapLine(org.springframework.batch.io.file.mapping.DefaultFieldSet)
*/
public Object mapLine(FieldSet fs) {
Object copy = getBean();

View File

@@ -0,0 +1,487 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.io.file.mapping;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Default implementation of {@link FieldSet} using Java using Java primitive
* and standard types and utilities. Strings are trimmed before parsing by
* default, and so are plain String values.
*
* @author Rob Harrop
* @author Dave Syer
*/
public class DefaultFieldSet implements FieldSet {
private final static String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";
/**
* The fields wrapped by this '<code>FieldSet</code>' instance.
*/
private String[] tokens;
private List names;
public DefaultFieldSet(String[] tokens) {
this.tokens = tokens == null ? null : (String[]) tokens.clone();
}
public DefaultFieldSet(String[] tokens, String[] names) {
Assert.notNull(tokens);
Assert.notNull(names);
if (tokens.length != names.length) {
throw new IllegalArgumentException("Field names must be same length as values: names="
+ Arrays.asList(names) + ", values=" + Arrays.asList(tokens));
}
this.tokens = (String[]) tokens.clone();
this.names = Arrays.asList(names);
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#getNames()
*/
public String[] getNames() {
if (names == null) {
throw new IllegalStateException("Field names are not known");
}
return (String[]) names.toArray();
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#getValues()
*/
public String[] getValues() {
return tokens;
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readString(int)
*/
public String readString(int index) {
return readAndTrim(index);
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readString(java.lang.String)
*/
public String readString(String name) {
return readString(indexOf(name));
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readBoolean(int)
*/
public boolean readBoolean(int index) {
return readBoolean(index, "true");
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readBoolean(java.lang.String)
*/
public boolean readBoolean(String name) {
return readBoolean(indexOf(name));
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readBoolean(int,
* java.lang.String)
*/
public boolean readBoolean(int index, String trueValue) {
Assert.notNull(trueValue, "'trueValue' cannot be null.");
String value = readAndTrim(index);
return trueValue.equals(value) ? true : false;
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readBoolean(java.lang.String,
* java.lang.String)
*/
public boolean readBoolean(String name, String trueValue) {
return readBoolean(indexOf(name), trueValue);
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readChar(int)
*/
public char readChar(int index) {
String value = readAndTrim(index);
Assert.isTrue(value.length() == 1, "Cannot convert field value '" + value + "' to char.");
return value.charAt(0);
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readChar(java.lang.String)
*/
public char readChar(String name) {
return readChar(indexOf(name));
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readByte(int)
*/
public byte readByte(int index) {
return Byte.parseByte(readAndTrim(index));
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readByte(java.lang.String)
*/
public byte readByte(String name) {
return readByte(indexOf(name));
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readShort(int)
*/
public short readShort(int index) {
return Short.parseShort(readAndTrim(index));
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readShort(java.lang.String)
*/
public short readShort(String name) {
return readShort(indexOf(name));
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readInt(int)
*/
public int readInt(int index) {
return Integer.parseInt(readAndTrim(index));
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readInt(java.lang.String)
*/
public int readInt(String name) {
return readInt(indexOf(name));
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readInt(int,
* int)
*/
public int readInt(int index, int defaultValue) {
String value = readAndTrim(index);
return StringUtils.hasLength(value) ? Integer.parseInt(value) : defaultValue;
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readInt(java.lang.String,
* int)
*/
public int readInt(String name, int defaultValue) {
return readInt(indexOf(name), defaultValue);
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readLong(int)
*/
public long readLong(int index) {
return Long.parseLong(readAndTrim(index));
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readLong(java.lang.String)
*/
public long readLong(String name) {
return readLong(indexOf(name));
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readLong(int,
* long)
*/
public long readLong(int index, long defaultValue) {
String value = readAndTrim(index);
return StringUtils.hasLength(value) ? Long.parseLong(value) : defaultValue;
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readLong(java.lang.String,
* long)
*/
public long readLong(String name, long defaultValue) {
return readLong(indexOf(name), defaultValue);
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readFloat(int)
*/
public float readFloat(int index) {
return Float.parseFloat(readAndTrim(index));
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readFloat(java.lang.String)
*/
public float readFloat(String name) {
return readFloat(indexOf(name));
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readDouble(int)
*/
public double readDouble(int index) {
return Double.parseDouble(readAndTrim(index));
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readDouble(java.lang.String)
*/
public double readDouble(String name) {
return readDouble(indexOf(name));
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readBigDecimal(int)
*/
public BigDecimal readBigDecimal(int index) {
return readBigDecimal(index, null);
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readBigDecimal(java.lang.String)
*/
public BigDecimal readBigDecimal(String name) {
return readBigDecimal(name, null);
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readBigDecimal(int,
* java.math.BigDecimal)
*/
public BigDecimal readBigDecimal(int index, BigDecimal defaultValue) {
String candidate = readAndTrim(index);
try {
return (StringUtils.hasText(candidate)) ? new BigDecimal(candidate) : defaultValue;
}
catch (NumberFormatException e) {
throw new IllegalArgumentException("Unparseable number: " + candidate);
}
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readBigDecimal(java.lang.String,
* java.math.BigDecimal)
*/
public BigDecimal readBigDecimal(String name, BigDecimal defaultValue) {
try {
return readBigDecimal(indexOf(name), defaultValue);
}
catch (IllegalArgumentException e) {
throw new IllegalArgumentException(e.getMessage() + ", name: [" + name + "]");
}
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readDate(int)
*/
public Date readDate(int index) {
return readDate(index, DEFAULT_DATE_PATTERN);
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readDate(java.lang.String)
*/
public Date readDate(String name) {
return readDate(name, DEFAULT_DATE_PATTERN);
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readDate(int,
* java.lang.String)
*/
public Date readDate(int index, String pattern) {
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
Date date;
String value = readAndTrim(index);
try {
date = sdf.parse(value);
}
catch (ParseException e) {
throw new IllegalArgumentException(e.getMessage() + ", pattern: [" + pattern + "]");
}
return date;
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#readDate(java.lang.String,
* java.lang.String)
*/
public Date readDate(String name, String pattern) {
try {
return readDate(indexOf(name), pattern);
}
catch (IllegalArgumentException e) {
throw new IllegalArgumentException(e.getMessage() + ", name: [" + name + "]");
}
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#getFieldCount()
*/
public int getFieldCount() {
return tokens.length;
}
/**
* Read and trim the {@link String} value at '<code>index</code>'.
*
* @throws NullPointerException if the field value is <code>null</code>.
*/
protected String readAndTrim(int index) {
String value = tokens[index];
if (value != null) {
return value.trim();
}
else {
return null;
}
}
/**
* Read and trim the {@link String} value from column with given '<code>name</code>.
*
* @throws IllegalArgumentException if a column with given name is not
* defined.
*/
protected int indexOf(String name) {
if (names == null) {
throw new IllegalArgumentException("Cannot access columns by name without meta data");
}
int index = names.indexOf(name);
if (index >= 0) {
return index;
}
throw new IllegalArgumentException("Cannot access column [" + name + "] from " + names);
}
public String toString() {
if (names != null) {
return getProperties().toString();
}
return tokens == null ? "" : Arrays.asList(tokens).toString();
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object object) {
if (object instanceof DefaultFieldSet) {
DefaultFieldSet fs = (DefaultFieldSet) object;
if (this.tokens == null) {
return fs.tokens == null;
}
else {
return Arrays.equals(this.tokens, fs.tokens);
}
}
return false;
}
public int hashCode() {
// this algorithm was taken from java 1.5 jdk Arrays.hashCode(Object[])
if (tokens == null) {
return 0;
}
int result = 1;
for (int i = 0; i < tokens.length; i++) {
result = 31 * result + (tokens[i] == null ? 0 : tokens[i].hashCode());
}
return result;
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.file.mapping.IFieldSet#getProperties()
*/
public Properties getProperties() {
if (names == null) {
throw new IllegalStateException("Cannot create properties without meta data");
}
Properties props = new Properties();
for (int i = 0; i < tokens.length; i++) {
String value = readAndTrim(i);
if (value != null) {
props.setProperty((String) names.get(i), value);
}
}
return props;
}
}

View File

@@ -1,652 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.io.file.mapping;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* @author Rob Harrop
* @author Dave Syer
*/
public class FieldSet {
private final static String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";
/**
* The fields wrapped by this '<code>FieldSet</code>' instance.
*/
private String[] tokens;
private List names;
public FieldSet(String[] tokens) {
this.tokens = tokens == null ? null : (String[]) tokens.clone();
}
public FieldSet(String[] tokens, String[] names) {
Assert.notNull(tokens);
Assert.notNull(names);
if (tokens.length != names.length) {
throw new IllegalArgumentException(
"Field names must be same length as values: names="
+ Arrays.asList(names) + ", values="
+ Arrays.asList(tokens));
}
this.tokens = (String[]) tokens.clone();
this.names = Arrays.asList(names);
}
/**
* Public accessor for the names property.
*
* @return the names
*
* @throws IllegalStateException if the names are not defined
*/
public String[] getNames() {
if (names == null) {
throw new IllegalStateException(
"Field names are not known");
}
return (String[]) names.toArray();
}
/**
* @return fields wrapped by this '<code>FieldSet</code>' instance as String values.
*/
public String[] getValues() {
return tokens;
}
/**
* Read the {@link String} value at index '<code>index</code>'.
*
* @param index
* the field index.
* @throws IndexOutOfBoundsException
* if the index is out of bounds.
*/
public String readString(int index) {
return readAndTrim(index);
}
/**
* Read the {@link String} value from column with given '<code>name</code>'.
*
* @param name
* the field name.
*/
public String readString(String name) {
return readString(indexOf(name));
}
/**
* Read the '<code>boolean</code>' value at index '<code>index</code>'.
*
* @param index
* the field index.
* @throws IndexOutOfBoundsException
* if the index is out of bounds.
*/
public boolean readBoolean(int index) {
return readBoolean(index, "true");
}
/**
* Read the '<code>boolean</code>' value from column with given '<code>name</code>'.
*
* @param name
* the field name.
* @throws IllegalArgumentException
* if a column with given name is not defined.
*/
public boolean readBoolean(String name) {
return readBoolean(indexOf(name));
}
/**
* Read the '<code>boolean</code>' value at index '<code>index</code>'.
*
* @param index
* the field index.
* @param trueValue
* the value that signifies {@link Boolean#TRUE true};
* case-sensitive.
* @throws IndexOutOfBoundsException
* if the index is out of bounds, or if the supplied
* <code>trueValue</code> is <code>null</code>.
*/
public boolean readBoolean(int index, String trueValue) {
Assert.notNull(trueValue, "'trueValue' cannot be null.");
String value = readAndTrim(index);
return trueValue.equals(value) ? true : false;
}
/**
* Read the '<code>boolean</code>' value from column with given '<code>name</code>'.
*
* @param name
* the field name.
* @param trueValue
* the value that signifies {@link Boolean#TRUE true};
* case-sensitive.
* @throws IllegalArgumentException
* if a column with given name is not defined, or if the
* supplied <code>trueValue</code> is <code>null</code>.
*/
public boolean readBoolean(String name, String trueValue) {
return readBoolean(indexOf(name), trueValue);
}
/**
* Read the '<code>char</code>' value at index '<code>index</code>'.
*
* @param index
* the field index.
* @throws IndexOutOfBoundsException
* if the index is out of bounds.
*/
public char readChar(int index) {
String value = readAndTrim(index);
Assert.isTrue(value.length() == 1, "Cannot convert field value '"
+ value + "' to char.");
return value.charAt(0);
}
/**
* Read the '<code>char</code>' value from column with given '<code>name</code>'.
*
* @param name
* the field name.
* @throws IllegalArgumentException
* if a column with given name is not defined.
*/
public char readChar(String name) {
return readChar(indexOf(name));
}
/**
* Read the '<code>byte</code>' value at index '<code>index</code>'.
*
* @param index
* the field index.
* @throws IndexOutOfBoundsException
* if the index is out of bounds.
*/
public byte readByte(int index) {
return Byte.parseByte(readAndTrim(index));
}
/**
* Read the '<code>byte</code>' value from column with given '<code>name</code>'.
*
* @param name
* the field name.
*/
public byte readByte(String name) {
return readByte(indexOf(name));
}
/**
* Read the '<code>short</code>' value at index '<code>index</code>'.
*
* @param index
* the field index.
* @throws IndexOutOfBoundsException
* if the index is out of bounds.
*/
public short readShort(int index) {
return Short.parseShort(readAndTrim(index));
}
/**
* Read the '<code>short</code>' value from column with given '<code>name</code>'.
*
* @param name
* the field name.
* @throws IllegalArgumentException
* if a column with given name is not defined.
*/
public short readShort(String name) {
return readShort(indexOf(name));
}
/**
* Read the '<code>int</code>' value at index '<code>index</code>'.
*
* @param index
* the field index.
* @throws IndexOutOfBoundsException
* if the index is out of bounds.
*/
public int readInt(int index) {
return Integer.parseInt(readAndTrim(index));
}
/**
* Read the '<code>int</code>' value from column with given '<code>name</code>'.
*
* @param name
* the field name.
* @throws IllegalArgumentException
* if a column with given name is not defined.
*/
public int readInt(String name) {
return readInt(indexOf(name));
}
/**
* Read the '<code>int</code>' value at index '<code>index</code>',
* using the supplied <code>defaultValue</code> if the field value is
* blank.
*
* @param index
* the field index..
* @throws IndexOutOfBoundsException
* if the index is out of bounds.
*/
public int readInt(int index, int defaultValue) {
String value = readAndTrim(index);
return StringUtils.hasLength(value) ? Integer.parseInt(value)
: defaultValue;
}
/**
* Read the '<code>int</code>' value from column with given '<code>name</code>',
* using the supplied <code>defaultValue</code> if the field value is
* blank.
*
* @param name
* the field name.
* @throws IllegalArgumentException
* if a column with given name is not defined.
*/
public int readInt(String name, int defaultValue) {
return readInt(indexOf(name), defaultValue);
}
/**
* Read the '<code>long</code>' value at index '<code>index</code>'.
*
* @param index
* the field index.
* @throws IndexOutOfBoundsException
* if the index is out of bounds.
*/
public long readLong(int index) {
return Long.parseLong(readAndTrim(index));
}
/**
* Read the '<code>long</code>' value from column with given '<code>name</code>'.
*
* @param name
* the field name.
* @throws IllegalArgumentException
* if a column with given name is not defined.
*/
public long readLong(String name) {
return readLong(indexOf(name));
}
/**
* Read the '<code>long</code>' value at index '<code>index</code>',
* using the supplied <code>defaultValue</code> if the field value is
* blank.
*
* @param index
* the field index..
* @throws IndexOutOfBoundsException
* if the index is out of bounds.
*/
public long readLong(int index, long defaultValue) {
String value = readAndTrim(index);
return StringUtils.hasLength(value) ? Long.parseLong(value)
: defaultValue;
}
/**
* Read the '<code>long</code>' value from column with given '<code>name</code>',
* using the supplied <code>defaultValue</code> if the field value is
* blank.
*
* @param name
* the field name.
* @throws IllegalArgumentException
* if a column with given name is not defined.
*/
public long readLong(String name, long defaultValue) {
return readLong(indexOf(name), defaultValue);
}
/**
* Read the '<code>float</code>' value at index '<code>index</code>'.
*
* @param index
* the field index.
* @throws IndexOutOfBoundsException
* if the index is out of bounds.
*/
public float readFloat(int index) {
return Float.parseFloat(readAndTrim(index));
}
/**
* Read the '<code>float</code>' value from column with given '<code>name</code>.
*
* @param name
* the field name.
* @throws IllegalArgumentException
* if a column with given name is not defined.
*/
public float readFloat(String name) {
return readFloat(indexOf(name));
}
/**
* Read the '<code>double</code>' value at index '<code>index</code>'.
*
* @param index
* the field index.
* @throws IndexOutOfBoundsException
* if the index is out of bounds.
*/
public double readDouble(int index) {
return Double.parseDouble(readAndTrim(index));
}
/**
* Read the '<code>double</code>' value from column with given '<code>name</code>.
*
* @param name
* the field name.
* @throws IllegalArgumentException
* if a column with given name is not defined.
*/
public double readDouble(String name) {
return readDouble(indexOf(name));
}
/**
* Read the {@link java.math.BigDecimal} value at index '<code>index</code>'.
*
* @param index
* the field index.
* @throws IndexOutOfBoundsException
* if the index is out of bounds.
*/
public BigDecimal readBigDecimal(int index) {
return readBigDecimal(index, null);
}
/**
* Read the {@link java.math.BigDecimal} value from column with given '<code>name</code>.
*
* @param name
* the field name.
* @throws IllegalArgumentException
* if a column with given name is not defined.
*/
public BigDecimal readBigDecimal(String name) {
return readBigDecimal(name, null);
}
/**
* Read the {@link BigDecimal} value at index '<code>index</code>',
* returning the supplied <code>defaultValue</code> if the trimmed string
* value at index '<code>index</code>' is blank.
*
* @param index
* the field index.
* @throws IndexOutOfBoundsException
* if the index is out of bounds.
*/
public BigDecimal readBigDecimal(int index, BigDecimal defaultValue) {
String candidate = readAndTrim(index);
try {
return (StringUtils.hasText(candidate)) ? new BigDecimal(candidate)
: defaultValue;
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Unparseable number: "
+ candidate);
}
}
/**
* Read the {@link BigDecimal} value from column with given '<code>name</code>,
* returning the supplied <code>defaultValue</code> if the trimmed string
* value at index '<code>index</code>' is blank.
*
* @param name
* the field name.
* @throws IllegalArgumentException
* if a column with given name is not defined.
*/
public BigDecimal readBigDecimal(String name, BigDecimal defaultValue) {
try {
return readBigDecimal(indexOf(name), defaultValue);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(e.getMessage() + ", name: ["
+ name + "]");
}
}
/**
* Read the <code>java.util.Date</code> value in default format at
* designated column <code>index</code>.
*
* @param index
* the field index.
* @param pattern
* the pattern describing the date and time format
* @throws IndexOutOfBoundsException
* if the index is out of bounds.
* @see #DEFAULT_DATE_PATTERN
*/
public Date readDate(int index) {
return readDate(index, DEFAULT_DATE_PATTERN);
}
/**
* Read the <code>java.sql.Date</code> value in given format from column
* with given <code>name</code>.
*
* @param name
* the field name.
* @param pattern
* the pattern describing the date and time format
* @throws IllegalArgumentException
* if a column with given name is not defined.
* @see #DEFAULT_DATE_PATTERN
*/
public Date readDate(String name) {
return readDate(name, DEFAULT_DATE_PATTERN);
}
/**
* Read the <code>java.util.Date</code> value in default format at
* designated column <code>index</code>.
*
* @param index
* the field index.
* @param pattern
* the pattern describing the date and time format
* @throws IndexOutOfBoundsException
* if the index is out of bounds.
* @throws IllegalArgumentException
* if the date cannot be parsed.
*
*/
public Date readDate(int index, String pattern) {
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
Date date;
String value = readAndTrim(index);
try {
date = sdf.parse(value);
} catch (ParseException e) {
throw new IllegalArgumentException(e.getMessage() + ", pattern: ["
+ pattern + "]");
}
return date;
}
/**
* Read the <code>java.sql.Date</code> value in given format from column
* with given <code>name</code>.
*
* @param name
* the field name.
* @param pattern
* the pattern describing the date and time format
* @throws IllegalArgumentException
* if a column with given name is not defined or if the
* specified field cannot be parsed
*
*/
public Date readDate(String name, String pattern) {
try {
return readDate(indexOf(name), pattern);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(e.getMessage() + ", name: ["
+ name + "]");
}
}
/**
* Return the number of fields in this '<code>FieldSet</code>'.
*/
public int getFieldCount() {
return tokens.length;
}
/**
* Read and trim the {@link String} value at '<code>index</code>'.
*
* @throws NullPointerException
* if the field value is <code>null</code>.
*/
private String readAndTrim(int index) {
String value = tokens[index];
if (value != null) {
return value.trim();
} else {
return null;
}
}
/**
* Read and trim the {@link String} value from column with given '<code>name</code>.
*
* @throws IllegalArgumentException
* if a column with given name is not defined.
*/
private int indexOf(String name) {
if (names == null) {
throw new IllegalArgumentException(
"Cannot access columns by name without meta data");
}
int index = names.indexOf(name);
if (index >= 0) {
return index;
}
throw new IllegalArgumentException("Cannot access column [" + name
+ "] from " + names);
}
public String toString() {
if (names != null) {
return getProperties().toString();
}
return tokens == null ? "" : Arrays.asList(tokens).toString();
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object object) {
if (object instanceof FieldSet) {
FieldSet fs = (FieldSet) object;
if (this.tokens == null) {
return fs.tokens == null;
} else {
return Arrays.equals(this.tokens, fs.tokens);
}
}
return false;
}
public int hashCode() {
// this algorithm was taken from java 1.5 jdk Arrays.hashCode(Object[])
if (tokens == null) {
return 0;
}
int result = 1;
for (int i = 0; i < tokens.length; i++) {
result = 31 * result
+ (tokens[i] == null ? 0 : tokens[i].hashCode());
}
return result;
}
/**
* Construct name-value pairs from the field names and string values. Null
* values are omitted.
*
* @return some properties representing the field set.
*
* @throws IllegalStateException
* if the field name meta data is not available.
*/
public Properties getProperties() {
if (names == null) {
throw new IllegalStateException(
"Cannot create properties without meta data");
}
Properties props = new Properties();
for (int i = 0; i < tokens.length; i++) {
String value = readAndTrim(i);
if (value != null) {
props.setProperty((String) names.get(i), value);
}
}
return props;
}
}

View File

@@ -19,6 +19,7 @@ package org.springframework.batch.io.file.transform;
import java.util.ArrayList;
import java.util.List;
import org.springframework.batch.io.file.mapping.DefaultFieldSet;
import org.springframework.batch.io.file.mapping.FieldSet;
@@ -63,7 +64,7 @@ public abstract class AbstractLineTokenizer implements LineTokenizer {
public FieldSet tokenize(String line) {
if (line == null || line.length()==0) {
return new FieldSet(new String[0]);
return new DefaultFieldSet(new String[0]);
}
List tokens = new ArrayList(doTokenize(line));
@@ -73,9 +74,9 @@ public abstract class AbstractLineTokenizer implements LineTokenizer {
String[] values = (String[]) tokens.toArray(new String[tokens.size()]);
if (names.length==0) {
return new FieldSet(values);
return new DefaultFieldSet(values);
}
return new FieldSet(values, names);
return new DefaultFieldSet(values, names);
}
protected abstract List doTokenize(String line);

View File

@@ -21,6 +21,7 @@ import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.batch.io.file.mapping.DefaultFieldSet;
import org.springframework.batch.io.file.mapping.FieldSet;
public class PrefixMatchingCompositeLineTokenizer implements LineTokenizer {
@@ -34,7 +35,7 @@ public class PrefixMatchingCompositeLineTokenizer implements LineTokenizer {
public FieldSet tokenize(String line) {
if (line==null) {
return new FieldSet(new String[0]);
return new DefaultFieldSet(new String[0]);
}
LineTokenizer tokenizer = null;