如何使用FieldSetMapper中的FieldSet处理空白非String值?

时间:2016-10-31 19:11:07

标签: java spring spring-batch

我正在使用通过搜索和StackOverflow中的示例找到的常见FieldSetMapper逻辑,我遇到了让我感到惊讶的情况。要么它是一个功能,要么是一个bug,但我想我会在这里进行审核,看看别人如何处理它。

使用Spring Batch,我有一个管道分隔文件,它有字符串和数字值,可以根据位置选择。例如:

string|string|number|number|string
string||number||string

在实现FieldSetMapper的字段集映射器类中,通常会执行一些映射,例如:

newThingy.setString1(fieldSet.readString("string1"));
newThingy.setString2(fieldSet.readString("string2"));
newThingy.setValue1(fieldSet.readInt("value1"));
newThingy.setValue2(fieldSet.readInt("value2"));
newThingy.setString3(fieldSet.readString("string3"));

在测试过程中,上面第1行的代码工作正常。 对于具有string2和value的空值的第2行,抛出了数字而不是字符串的Java异常:

Caused by: java.lang.NumberFormatException: Unparseable number: 
    at org.springframework.batch.item.file.transform.DefaultFieldSet.parseNumber(DefaultFieldSet.java:754)
    at org.springframework.batch.item.file.transform.DefaultFieldSet.readInt(DefaultFieldSet.java:323)
    at org.springframework.batch.item.file.transform.DefaultFieldSet.readInt(DefaultFieldSet.java:335)
    at com.healthcloud.batch.mapper.MemberFieldSetMapper.mapFieldSet(MemberFieldSetMapper.java:31)
    at com.healthcloud.batch.mapper.MemberFieldSetMapper.mapFieldSet(MemberFieldSetMapper.java:1)

我在Spring Batch提供的DefaultFieldSetMapper.java类中做了一些研究,它实现了FieldSet类来试图理解发生了什么。

我发现readString调用的readAndTrim函数如果读取的值为空则返回null

protected String readAndTrim(int index) {
    String value = tokens[index];

    if (value != null) {
        return value.trim();
    }
    else {
        return null;
    }
}

...但是当使用readInt(或许还有其他)时,我们会返回一个异常。

private Number parseNumber(String candidate) {
    try {
        return numberFormat.parse(candidate);
    }
    catch (ParseException e) {
        throw new NumberFormatException("Unparseable number: " + candidate);
    }
}

我确实看到在某些方法中可以返回默认值的位置,但显然不允许使用null。我期望的是FieldSet实现中的所有方法之间的一致行为,它允许在读取数据时将文件与我的数据库匹配。分隔和固定长度文件中的空白值相当常见。

如果无法正确处理基于数字的值,我可能必须将所有内容转换为String,因为它被读取然后经历麻烦到手动处理转换到数据库,这显然违背了使用Spring Batch的目的。

我错过了一些我应该处理得更好的东西吗?如果需要,我可以添加更多代码,我只觉得这是常用的,我可以保持这个简短。将根据需要进行编辑。

编辑:添加有关为Spring Batch类找到的单元测试的信息

测试用例状态中的注释应该设置默认值,但为什么呢?我不想要默认。我的数据库允许在Integer列中使用空值。我必须将默认设置为某个任意数字,希望没有人发送,在插入之前检查它,然后在插入时切换为null。我仍然不喜欢这个“功能”。

@Test
public void testReadBlankInt() {

    // Trying to parse a blank field as an integer, but without a default
    // value should throw a NumberFormatException
    try {
        fieldSet.readInt(13);
        fail();
    }
    catch (NumberFormatException ex) {
        // expected
    }

    try {
        fieldSet.readInt("BlankInput");
        fail();
    }
    catch (NumberFormatException ex) {
        // expected
    }

}

1 个答案:

答案 0 :(得分:0)

始终健全检查您的输入/数据。我通常会将Util类与所需的所有解析/读取/验证结合在一起。下面的裸骨版......

public static Integer getInteger(FieldSet fs, String key, Integer default) {
    if(StringUtils.isNumeric(fs.readString(key)) {
        return fs.readInt(key);
    } else {
        return default;
    }
}