问题
I'm using openCsv library cause it's very easy to use and I got all necessary functional. But now I need to use some custom logic except checking for correct types, columns and other usual things. I have a csv with columns firstName
, secondName
, firstSalary
, lastSalary
and others. I want to check that firstDayOfWork
is less than lastDayOfWork
in the process of parcing and add a new csvException if it is false. So, if now I'm parcing file
firstName,secondName,firstSalary,lastSalary
John, Doe, testtext, 5000
Alice, , 100, 5000
Harry, Smith, 400, 200
and processing a list of csvExcpetions I can get results of parcing like
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.
I want to something like
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
Or some custom parcing logic like check if some field catch regexp, two fields at the same time greater than 0, etc.
I can firstly parce and convert it to beans and by the second cycle check my beans to these rules, but there are can be a lot of lines and it will take longer, so, I want to check it in the one process.
Can I get it by openCsv? And if yes, how? If no, what another tool I can use? Thank you.
回答1:
While there is a request on the todo/wish list for OpenCSV I don't think it will help you because it's about pre parsing validation
For what you want you should just add a check in your setters to throw an exception when the values are bad. Here is my Bean and test.
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();
}
}
And here is the result.
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
Hope that helps.
Scott Conway :)
来源:https://stackoverflow.com/questions/48691164/opencsv-custom-logic-in-parcing