Search code examples
javaopencsvconverters

How do I build a (working) custom converter with opencsv


I'm using OpenCSV with a nested bean structure. However, I need a custom converter to pull this off (currently focussing on the writing to csv part). I've looked around but I've not found any examples to help me figure out how to make it work.

I've tried extending my child bean Class, and some conversions provided in the main documentation. But I've run out of sources, the farthest I've come is getting it to throw a CsvBadConverterException.

Let me show you what I have. (Both User and UserScore implement Serializable, just in case that helps.) Parent bean: User

    @CsvBindByName(column = "username")
    private String userName;
    @CsvBindByName(column = "password")
    private String userPassword;
    @CsvBindByName(column = "rememberPassword")
    private boolean rememberPassword;
    @CsvBindByName(column = "rememberUser")
    private boolean rememberUser;
    @CsvCustomBindByName(column = "scores", converter = UserScoreToBean.class)
    private UserScore userScore;

    // Constructors, getters, setters, and other methods

Child bean: UserScore

    @CsvBindByName(column = "totalScore")
    private int totalScore;
    @CsvBindByName(column = "currentScore")
    private int currentScore;
    @CsvBindByName(column = "highestStreak")
    private int highestStreak;

    // Even more basic getter, setter, etc.

Converter: UserScoreToBean

    public abstract class UserScoreToBean extends AbstractBeanField<User> {
    @Override
    protected Object convert(String s) {
        UserScore score = new UserScore();
        String[] split = s.split(".", 3);
        score.setTotalScore(Integer.valueOf(split[0]));
        score.setCurrentScore(Integer.valueOf(split[1]));
        score.setHighestStreak(Integer.valueOf(split[2]));
        return score;
//        return null;
    }

    @Override
    protected String convertToWrite(Object value) throws CsvDataTypeMismatchException, CsvRequiredFieldEmptyException {
        UserScore score = (UserScore) value;

        return "\"" + score.getTotalScore() + "." + score.getCurrentScore() + "." + score.getHighestStreak() + "\"";
//        return super.convertToWrite(value);
    }
    }

As you can see my converter is hecking basic. So I'd love any and all help you can provide. For ease of troubleshooting I've just got my program to try and generate a header on start which gives me this exception:

com.opencsv.exceptions.CsvBadConverterException: There was a problem instantiating the custom converter settings.user.UserScoreToBean.

Thanks for reading!


Solution

  • Use opencsv 5.0 and its new annotation @CsvRecurse. Items from nested objects will then appear in the csv as top level.

    If you for whatever reason cannot change library, then I would take a look on CsvBindAndSplitByName" annotation, but it will require some tweaking.