Search code examples
javaconstructoropencsv

Why does com.opencsv.bean.CsvToBeanBuilder fail when my bean has a constructor?


I want to read in a csv file once, and later request information from it. Later this is going to be in a website/Rest-API. I am new to the world of java-website-development, but I hope this way is the way to do it:

I create a class that reads in the data (I want that this happens once, so I use a static variable for that).

When the csv is read in by opencsv, the data are stored in a bean. For this I create the Car-class as a bean.

I use a third class to do the processing and the logic. Later this is supposed to be the website that processes the data.

Here are the classes:

The bean:

Car.java

package org.example;

import com.opencsv.bean.CsvBindByName;

import java.math.BigDecimal;

public class Car {

    @CsvBindByName
    private int id;
    @CsvBindByName(column = "name")
    private String brand;
    @CsvBindByName
    private BigDecimal price;



    public int getId() {
        return id;
    }

    public String getBrand() {
        return brand;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }


    public void setBrand(String brand) {
        this.brand = brand;
    }

    @Override
    public String toString() {
        return "Car{" +
                "id=" + id +
                ", brand='" + brand + '\'' +
                ", price=" + price +
                '}';
    }
}

abc.csv:

id,name,price
1,Audi,52642
2,Mercedes,57127
3,Skoda,9000
4,Volvo,29000
5,Bentley,350000
6,Citroen,21000
7,Hummer,41400
8,Volkswagen,21600
9,Toyota,26700

ReadCSVFile.java

package org.example;

import com.opencsv.bean.CsvToBeanBuilder;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.List;

public class ReadCSVFile {
    static String fileName = "src/main/resources/abc.csv";
    public static List<Car> cars;

    static {
        try {
            cars = new CsvToBeanBuilder(new FileReader(fileName))
                    .withType(Car.class).build().parse();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }


}

Main.java

package org.example;

import com.opencsv.CSVReader;

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello world!");

        System.out.println();
        for (Car car : ReadCSVFile.cars) {
            System.out.println(car.toString());
        }
        Scanner sc = new Scanner(System.in);
        for (int i = 0; i < 10; i++) {

            System.out.println("Enter id to get more details about the car.");
            int id_number = sc.nextInt();
            System.out.println("Your selected id is "+id_number);
            Car selected_car = null;
            for (Car car : ReadCSVFile.cars) {
                if (car.getId() == id_number) {
                    selected_car = car;
                }
            }
            if (selected_car == null) {
                System.out.println("No car found that matches your id.");
            } else {
                System.out.println("Selected car matches: " + selected_car.toString());
            }
            System.out.println();
        }
    }
}

This works fine, but when I add a constructor in the Car.java

public Car(int id, String brand, BigDecimal price) {
        this.id = id;
        this.brand = brand;
        this.price = price;
    }

then I get an error: Caused by: java.lang.RuntimeException: com.opencsv.exceptions.CsvBeanIntrospectionException: Instantiierung des angegebenen Typs (und eventuell vorhandene Untertypen) ist unm�glich.

I do not know how to switch this error message to English; it means something like "It is not possible to instantiate the wanted type (and possibly also present subtypes)".

Does opencsv generally have problems with constructors? Is this a wanted behaviour? Do beans generally lack constructors? Because I feel like I want to have a constructor in the future in my class...

Please feel free to add comments about my general approach how I organize the code.


Solution

  • OpenCSV‘s introspection works by creating object instances via a no-args constructor. Therefore, you are required to provide one, even if you have specialized constructors as posted in your question.

    By default, there will be a no-arg constructor in Java, however, once you have a custom one, the no-arg one must be explicitly defined in your Java class.

    To cure the problem, just add back in a no-arg constructor, eg in a protected form:

    protected Car() {}
    

    This way, the code should just work fine at runtime.