【问题标题】:How do you handle blank non String values with a FieldSet in FieldSetMapper?如何使用 FieldSetMapper 中的 FieldSet 处理空白的非字符串值?
【发布时间】:2016-10-31 19:11:06
【问题描述】:

我正在使用通过搜索和 StackOverflow 上的示例找到的常见 FieldSetMapper 逻辑,我遇到了让我感到惊讶的情况。它要么是一个功能,要么是一个错误,但我想我会在这里展示它以供审查,看看其他人如何处理它。

使用 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 实现中所有方法之间的一致行为,允许在读取数据时将文件与我的数据库匹配。分隔和固定长度文件中的空白值相当普遍。

如果不能正确处理基于数字的值,我可能不得不在读取所有内容时将其转换为字符串,然后费力手动处理转换为数据库,这显然违背了使用 Spring Batch 的目的.

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

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

测试用例中的 cmets 表明应该设置默认值,但为什么呢?我不想要默认值。我的数据库允许 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
    }

}

【问题讨论】:

  • 请使用来自 Apache Commons Lang 的 NumberUtils.toInt。签名是 public static int NumberUtils.toInt(java.lang.String str, int defaultValue)
  • 你找到解决问题的方法了吗,我也有同样的问题。

标签: java spring spring-batch


【解决方案1】:

始终检查您的输入/数据。我通常会将 Util 类与我需要的所有解析/读取/验证放在一起。下面是裸机版本...

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

【讨论】:

  • 我写这篇文章的真正目的是提醒大家注意 readInt 处理 null 的方式与 readString 不同,我们不应该自己做这个级别的工作。另外,不能只使用 newThingy.setValue1(fieldSet.readInt("value1", DEFAULT_VALUE));代替?
  • 如果 readInt 返回 Integer 而不是 int,他们当然可以继续并返回 null。但它返回一个 int,这意味着它们不能返回 null。因此抛出异常。此外,我使用上面的方法是因为大多数时候我的默认值为 null。这是 readInt(String, int) 方法做不到的。
  • 看起来有一百万个 StringUtils 的实现。你能分享你的进口声明吗?
  • @TheJeff 等了一分钟,但可能是 Apache Commons
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-21
  • 2018-07-04
  • 1970-01-01
相关资源
最近更新 更多