BeanIO中record级别minLength校验失效问题求助
BeanIO minLength校验失效问题排查与解决
问题描述
配置BeanIO映射文件处理分隔符文件时,required校验可正常生效,但minLength校验失效。例如输入中Gregory记录的salary字段为空时,未触发minLength="1"的错误提示。
映射文件配置
<record name="detail" minOccurs="0" maxOccurs="unbounded" class="com.test.Person"> <field name="firstName"/> <field name="surname"/> <field name="salary" minLength="1"/> <field name="age" required="true"/> </record>
输入内容
John|Smith|300000.00|34 Peter|William|800000.00| Gregory|Rocky||30
输出结果
[Person [firstName=John, surname=Smith, salary=300000.0, age=34], Person [firstName=Gregory, surname=Rocky, salary=0.0, age=30]] Errors: 3 : age : [Required field not set]
Java代码
public void readCSVFileUsingBeanIo() throws FileNotFoundException { StreamFactory factory = StreamFactory.newInstance(); factory.loadResource("person.xml"); StringBuilder rejects = new StringBuilder(); // 从类路径读取文件:src/main/resources InputStream in = new FileInputStream(new File( "person.csv")); BeanReader reader = factory.createReader("persons", new InputStreamReader(in)); reader.setErrorHandler(new BeanReaderErrorHandlerSupport() { public void invalidRecord(InvalidRecordException ex) throws Exception { for (int i = 0, j = ex.getRecordCount(); i < j; i++) { final int ii = i; if (ex.getRecordContext(i).hasErrors()) { ex.getRecordContext(i).getFieldErrors().keySet().stream().forEach(key -> { rejects.append("\n"); rejects.append(ex.getRecordContext(ii).getLineNumber() + " : "); rejects.append(ex.getRecordContext(ii).getRecordText() + " Field(" + key + ") : Error " + ex.getRecordContext(ii).getFieldErrors(key)); }); rejects.append("\n"); } } } }); Object record = null; List<Person> persons = new ArrayList<>(); while ((record = reader.read()) != null) { if ("header".equals(reader.getRecordName())) { @SuppressWarnings("unchecked") Map<String, Object> header = (Map<String, Object>) record; System.out.println(header.get("fileDate")); } else if ("detail".equals(reader.getRecordName())) { Person person = (Person) record; persons.add(person); } } System.out.println(persons); System.out.println("Errors:"); System.out.println(rejects); }
原因分析
BeanIO中minLength校验仅针对字符串类型字段的原始输入文本长度生效。当字段为数值类型(如salary对应Java类中的double类型)时,空字符串输入会被自动转换为该数值类型的默认值(double默认值为0.0),此时minLength校验不会触发——因为数值类型不存在"长度"属性,BeanIO不会对其应用文本长度校验规则。
解决方案
方案1:添加required校验(推荐,适用于不允许salary为空的场景)
直接给salary字段添加required="true"属性,强制校验字段不能为空,与age字段的校验逻辑一致:
<field name="salary" minLength="1" required="true"/>
此时空的salary输入会触发必填错误,符合业务预期。
方案2:将字段类型改为字符串(适用于需要校验输入文本长度的场景)
如果需要严格校验输入的文本长度(例如确保输入至少有1个字符),将salary字段的类型设为字符串,后续在Java代码中自行处理数值转换:
<field name="salary" type="java.lang.String" minLength="1"/>
对应的Java类中salary字段改为String类型,之后可通过Double.parseDouble()等方式转换为数值,空字符串输入会直接触发minLength校验错误。
方案3:自定义类型处理器(适用于复杂校验场景)
实现自定义TypeHandler,在解析空字符串输入时抛出异常,结合minLength校验实现自定义逻辑:
public class CustomDoubleTypeHandler extends AbstractTypeHandler { @Override public Object parse(String text) throws TypeConversionException { if (text == null || text.trim().isEmpty()) { throw new TypeConversionException("Salary cannot be empty"); } try { return Double.parseDouble(text); } catch (NumberFormatException e) { throw new TypeConversionException("Invalid salary format"); } } @Override public String format(Object value) { return value != null ? value.toString() : ""; } }
然后在映射文件中配置使用该处理器:
<field name="salary" typeHandler="com.test.CustomDoubleTypeHandler" minLength="1"/>
内容的提问来源于stack exchange,提问作者Jericho
相关产品推荐
相关产品推荐

