簡體   English   中英

解析中的Opencsv自定義邏輯

[英]Opencsv custom logic in parsing

我正在使用 openCsv 庫,因為它非常易於使用並且我獲得了所有必要的功能。 但是現在我需要使用一些自定義邏輯,除了檢查正確的類型、列和其他常見的東西。 我有一個包含firstNamesecondNamefirstSalarylastSalary等列的 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,您可以:

  1. 創建一個 BeanVerifier 以在創建后驗證整個 bean;
  2. 出錯時拋出CsvConstraintViolationException
  3. .withThrowExceptions(false)添加到CsvToBeanBuilder
  4. 調用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM