[英]Opencsv custom logic in parsing
我正在使用 openCsv 庫,因為它非常易於使用並且我獲得了所有必要的功能。 但是現在我需要使用一些自定義邏輯,除了檢查正確的類型、列和其他常見的東西。 我有一個包含firstName
、 secondName
、 firstSalary
、 lastSalary
等列的 csv。 我想在lastDayOfWork
過程中檢查firstDayOfWork
是否小於lastDayOfWork
,如果為false則添加一個新的csvException。 所以,如果現在我正在整理文件
firstName,secondName,firstSalary,lastSalary
John, Doe, testtext, 5000
Alice, , 100, 5000
Harry, Smith, 400, 200
並處理一個 csvExcpetions 列表,我可以獲得像
Number of mistakes: 2
Line 1: Conversion of testtext to java.lang.Integer failed.
Line 2: Field 'secondName' is mandatory but no value was provided.
我想要類似的東西
Number of mistakes: 3
Line 1: Conversion of testtext to java.lang.Integer failed.
Line 2: Field 'secondName' is mandatory but no value was provided.
Line 3: firstSalary cannot be more than lastSalary
或者一些自定義的解析邏輯,例如檢查某個字段是否捕獲正則表達式、兩個字段是否同時大於 0 等。
我可以首先將其打包並將其轉換為 bean,然后在第二個周期檢查我的 bean 是否符合這些規則,但可能有很多行並且需要更長的時間,因此,我想在一個過程中檢查它。
我可以通過 openCsv 獲取嗎? 如果是,如何? 如果沒有,我可以使用什么其他工具? 謝謝。
雖然在 OpenCSV 的待辦事項/願望清單上有一個請求,但我認為它不會幫助你,因為它是關於預解析驗證的
對於你想要的,你應該在你的 setter 中添加一個檢查,當值不好時拋出異常。 這是我的 Bean 和測試。
public class SetterBean {
@CsvBindByName(column = "First Name", required = true)
private String firstName;
@CsvBindByName(column = "Last Name", required = true)
private String lastName;
@CsvBindByName(column = "First Salary")
private Long firstSalary;
@CsvBindByName(column = "Last Salary")
private Long lastSalary;
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void setFirstSalary(Long firstSalary) {
if (lastSalary != null && (firstSalary.compareTo(lastSalary) > 0)) {
throw new IllegalArgumentException("First Salary cannot be greater than Last Salary.");
}
this.firstSalary = firstSalary;
}
public void setLastSalary(Long lastSalary) {
if (firstSalary != null && (lastSalary.compareTo(firstSalary) < 0)) {
throw new IllegalArgumentException("Last Salary cannot be less than First Salary.");
}
this.lastSalary = lastSalary;
}
}
public class SetterValidationTest {
private static final String HEADER = "First Name,Last Name,First Salary,Last Salary\n";
CsvToBean<SetterBean> csvToBean;
@Test
public void normalData() {
String data = HEADER + "First, Last, 1, 2";
csvToBean = new CsvToBeanBuilder<SetterBean>(new StringReader(data))
.withType(SetterBean.class)
.build();
List<SetterBean> beans = csvToBean.parse();
assertEquals(1, beans.size());
}
@Test(expected = Exception.class)
public void firstGTLast() {
String data = HEADER + "First, Last, 2, 1";
csvToBean = new CsvToBeanBuilder<SetterBean>(new StringReader(data))
.withType(SetterBean.class)
.build();
List<SetterBean> beans = csvToBean.parse();
}
}
這是結果。
Exception in thread "pool-1-thread-1" java.lang.RuntimeException: com.opencsv.exceptions.CsvDataTypeMismatchException
at com.opencsv.bean.concurrent.ProcessCsvLine.run(ProcessCsvLine.java:91)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
Caused by: com.opencsv.exceptions.CsvDataTypeMismatchException
at com.opencsv.bean.AbstractBeanField.assignValueToField(AbstractBeanField.java:192)
at com.opencsv.bean.AbstractBeanField.setFieldValue(AbstractBeanField.java:159)
at com.opencsv.bean.concurrent.ProcessCsvLine.processField(ProcessCsvLine.java:140)
at com.opencsv.bean.concurrent.ProcessCsvLine.processLine(ProcessCsvLine.java:126)
at com.opencsv.bean.concurrent.ProcessCsvLine.run(ProcessCsvLine.java:82)
... 3 more
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.opencsv.bean.AbstractBeanField.assignValueToField(AbstractBeanField.java:187)
... 7 more
Caused by: java.lang.IllegalArgumentException: Last Salary cannot be less than First Salary.
at integrationTest.BeanTests.SetterBean.setLastSalary(SetterBean.java:33)
... 12 more
希望有幫助。
斯科特康威 :)
基於如何通過使用 OpenCsv 記錄無效記錄的錯誤來創建有效 CSV 記錄的列表? ,而不是在 setter 中拋出 IllegalArgumentException,您可以:
CsvConstraintViolationException
;.withThrowExceptions(false)
添加到CsvToBeanBuilder
;getCapturedExceptions()
以收集驗證錯誤。此解決方案的優點是您可以根據需要收集 CSV 異常列表:
示例
final CsvToBean<EmployeeBean> csvToBean =
new CsvToBeanBuilder<EmployeeBean>(new FileReader("c:\\test.csv"))
.withType(EmployeeBean.class)
.withVerifier(new EmployeeSalaryVerifier())
.withThrowExceptions(false)
.build();
final List<EmployeeBeans> employees = csvToBean.parse();
List<CsvException> exceptions = parser.getCapturedExceptions();
// logging number of mistakes and, for each exception, its line number and message
logger.error("Number of Mistakes: {}", exceptions.size());
employees.getCapturedExceptions().stream().forEach(ex ->
logger.error("Line {}: {}", ex.getLineNumber(), ex.getMessage(), ex));
員工豆
public class EmployeeBean {
@CsvBindByName(column = "First Name", required = true)
private String firstName;
@CsvBindByName(column = "Last Name", required = true)
private String lastName;
@CsvBindByName(column = "First Salary" required = true)
private Long firstSalary;
@CsvBindByName(column = "Last Salary")
private Long lastSalary;
// regular getters and setters, no validation here
}
Bean驗證器
public class EmployeeSalaryVerifier implements BeanVerifier<EmployeeBean> {
@Override
public boolean verifyBean(Employee bean) throws CsvConstraintViolationException {
// check salary
if (bean.getLastSalary() != null && bean.getFirstSalary().compareTo(bean.getLastSalary()) > 0) {
throw new CsvConstraintViolationException("First Salary cannot be greater than Last Salary.");
}
return true;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.