Reputation: 2798
I have a CSV of the following format:
New CSV file
header_1,header_2,header_3,header_4
value_1,value_2,value_3,value_4
value_1,value_2,value_3,value_4
value_1,value_2,value_3,value_4
I have the following code for parsing this CSV:
CsvMapper csvMapper = new CsvMapper();
CsvSchema schema = CsvSchema.emptySchema().withSkipFirstDataRow(true);
List<CsvModel> rows = new LinkedList<>();
MappingIterator<CsvModel> iterator = csvMapper
.readerFor(CsvModel.class).with(schema)
.readValues(filePath.toFile());
while (iterator.hasNext()) {
CsvModel csvElement = iterator.next();
if (StringUtils.isBlank(csvElement.getValue1())) {
// skip lines not having the value
continue;
}
rows.add(csvElement);
}
However, I am getting the following exception while parsing the above mentioned CSV-format file:
com.fasterxml.jackson.databind.RuntimeJsonMappingException: Can not construct instance of com.adapters.CsvParsing: no String-argument constructor/factory method to deserialize from String value ('')
at [Source: com.fasterxml.jackson.dataformat.csv.impl.UTF8Reader@2cb566f1; line: 2, column: 1]
This is because the second line is empty. I need to skip the first two lines, how do I tell jackson to skip the first two lines of the file?
Edit 1: Here is the CsvModel file:
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class CsvModel {
public static final String IdField = "Id";
public static final String NameField = "Name";
public static final String GuidField = "Guid";
public static final String SubscriptionNameField = "Subscription Name";
public static final String DateField = "Date";
public static final String CostField = "Cost";
@JsonProperty(IdField)
private String Id;
@JsonProperty(NameField)
private String Name;
@JsonProperty(GuidField)
private String Guid;
@JsonProperty(SubscriptionNameField)
private String SubscriptionName;
@JsonProperty(DateField)
private String Date;
private Long epochDate;
@JsonProperty(CostField)
private Double Cost;
public String getId() {
return this.Id;
}
public void setId(String id) {
this.Id = id;
}
public String getName() {
return this.Name;
}
public void setName(String name) {
this.Name = name;
}
public String getGuid() {
return this.Guid;
}
public void setGuid(String guid) {
this.Guid = guid;
}
public String getSubscriptionName() {
return this.SubscriptionName;
}
public void setSubscriptionName(String subscriptionName) {
this.SubscriptionName = subscriptionName;
}
public String getDate() {
return this.Date;
}
public void setDate(String date) {
this.Date = date;
}
public Long getEpochDate() {
return this.epochDate;
}
public void setEpochDate(Long epochDate) {
this.epochDate = epochDate;
}
public Double getCost() {
return this.Cost;
}
public void setCost(Double cost) {
this.Cost = cost;
}
}
Upvotes: 1
Views: 9579
Reputation: 161
If anyone is still looking for a solution:
File tempFile = new File(tempLocation + csvFile.getName()); // tempLocation as per your choice
List<String> lines = FileUtils.readLines(csvFile, encoding); // apache.commons - FileUtils
if(!importingFile.exists())
importingFile.createNewFile();
int lineNum = 0;
PrintWriter printWriter = new PrintWriter(importingFile, "UTF-8");
for(String line : lines){
if(lineNum == 0){ continue; } // Skip the first line, if required
/**
* Here removes all special characters other than numbers and alphabets.
* Because in my case there was some unknown characters in the file.
*/
String filtered = line.replaceAll("[^a-zA-Z0-9]", "");
if( null == filtered || "".equals(filtered.trim()))){
continue;
}
printWriter.println(line);
lineNum++;
}
if(printWriter != null) printWriter.close();
CsvMapper mapper = new CsvMapper(); // jackson.dataformat - CsvMapper
mapper.enable(CsvParser.Feature.SKIP_EMPTY_LINES);
CsvSchema schema = mapper.schemaFor(CsvModel.class).withHeader()
.withColumnSeparator(';')
.withColumnReordering(true);
ObjectReader reader = mapper.readerFor(CsvModel.class).with(schema);
List list = reader.readValues(new FileInputStream(tempFile)).readAll();
Upvotes: 0
Reputation: 611
To skip empty lines you can use SKIP_EMPTY_LINES feature:
CsvMapper csvMapper = new CsvMapper().enable(CsvParser.Feature.SKIP_EMPTY_LINES);
CsvSchema schema = csvMapper.emptySchema().withSkipFirstDataRow(true);
MappingIterator<Account> dataIterator = csvMapper.readerFor(CsvModel.class).with(schema)
.readValues(file);
Upvotes: 5
Reputation: 1476
A better answer will be to consume the first few lines using BufferedReader.readLine()
.
Refer to this Apache commons csv skip lines.
Sample code:
try (final BufferedReader reader = new BufferedReader(new FileReader(csvFile))) {
// consume the first few lines here
reader.readLine();
reader.readLine();
final MappingIterator<MyClass> readValues =
new CsvMapper()
.readerFor(MyClass.class)
.with(emptySchema()
.withHeader()
.withNullValue(""))
.readValues(reader);
final List<MyClass> records = readValues.readAll();
} catch (Exception e) {
log.warn("Failed to read detail section of transactionItem file.");
}
Upvotes: 1
Reputation: 30819
You can skip the first two rows by advancing the iterator twice before processing, e.g.:
for(int i=0 ; i<2 ; i++){
if(iterator.hasNext()){
iterator.next();
}
}
while (iterator.hasNext()) {
...
This will make sure no Exception
gets thrown if let's say the file has less than 2 records.
Update
Editing the answer based on question edits:
The reason why it throws RuntimeJsonMappingException
is because it is interpreting one line of vsc file as a string and is trying to bind String
to CsvModel
object. You need to specify a (non empty) schema
with csvMapper
mapper which acts as metadata
while deserializing one line, e.g.:
CsvSchema schema = CsvSchema.builder()
.setColumnSeparator(',')
.addColumn("Id")
.addColumn("name")
....
You can have a look at this example.
Upvotes: 1