David
David

Reputation: 20063

Parsing csv via column order in spring batch

I've got a CSV in the format...

Kitten URL,Kitten Name,# of Reviews,Rating,Categories,,,,,,,,,,,,,
www.happykitten.com,happykittem.com,111746,7.8,Clothes & Fashion,Fashion Accessories,Ladies wear,Menswear,,,,,,,,,,
animedkitten.co.uk,Animed Kitten,33918,9.6,Pets,,,,,,,,,,,,,

So the first columns are Kitten URL,Kitten Name,# of Reviews,Rating then the rest are the possible categories listed as extra properties.

I'm trying to use Spring batch so I'm specifying the dumb object to represent this CSV. The first problem I've got is (using the example from Spring documentation I don't see how I can parse a CSV with spaces in the title. Is it possible to use Spring batch like this? Can I annotate each getting like in Hibernate with the title of the csv column?

My dumb object was going to be something like...

public class ImportDataObject {
    private String kittenUrl;
    private String kittenName;
    private int numOfReviews;
    public String getKittenUrl() {
        return kittenUrl;
    }
    public void setKittenUrl(String kittenUrl) {
        this.kittenUrl = kittenUrl;
    }
    public String getKittenName() {
        return kittenName;
    }
    public void setKittenName(String kittenName) {
        this.kittenName = kittenName;
    }
    public int getNumOfReviews() {
        return numOfReviews;
    }
    public void setNumOfReviews(int numOfReviews) {
        this.numOfReviews = numOfReviews;
    }

}

I only really want to read the first 2 columns, append some strings, then persist the rest of the CSV.

I'm also considering the best approach to use for these multiple commas afterwards. Unfortunately this is how I've got the data and it's not something I can change.

Upvotes: 0

Views: 1379

Answers (1)

Nenad Bozic
Nenad Bozic

Reputation: 3784

You can implement FieldSetMapper for your object and then set it to your DefaultLineMapper. Your implementation of FieldSetMapper can work on positions and you can parse only first few positions and set it to your bean.

Here is suggestion based on code from URL you posted:

reader.setLineMapper(new DefaultLineMapper<ImportDataObject>());
            setFieldSetMapper(new ImportDataObjectFieldSetMapper());
            }});
            setLinesToSkip(1); //skip header since read int will throw exception and I assume you do not need header info
        }});

Then changes to POJO object to save list of categories:

public class ImportDataObject {
    private String kittenUrl;
    private String kittenName;
    private int numOfReviews;
    private int rating; //add getters and setters
    private List<String> categories; //add getters and setters
    public String getKittenUrl() {
        return kittenUrl;
    }
    public void setKittenUrl(String kittenUrl) {
        this.kittenUrl = kittenUrl;
    }
    public String getKittenName() {
        return kittenName;
    }
    public void setKittenName(String kittenName) {
        this.kittenName = kittenName;
    }
    public int getNumOfReviews() {
        return numOfReviews;
    }
    public void setNumOfReviews(int numOfReviews) {
        this.numOfReviews = numOfReviews;
    }

}

And here is FieldSetMapper:

public class ImportDataObjectFieldSetMapper implements FieldSetMapper<ImportDataObject> {

    @Override
    public ImportDataObject mapFieldSet(final FieldSet fieldSet) throws BindException {
        final ImportDataObject importDataObject = new ImportDataObject();

        importDataObject.setKittenUrl(fieldSet.readString(0));
        importDataObject.setKittenName(fieldSet.readString(1));
        importDataObject.setNumOfReviews(fieldSet.readInt(2));
        importDataObject.setRating(fieldSet.readInt(3));

        importDataObject.setCategories(new ArrayList<String>());
        for (int i = 4; i < fieldSet.getFieldCount(); i++) {
            importDataObject.getCategories().add(fieldSet.readString(i));
        }


        return importDataObject;
    }
}

Upvotes: 3

Related Questions