【发布时间】: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