How to Read a CSV file with Header in Java using Jackson with Example

Hello guys, today I am going to show you how to read a CSV file in Java with a simple example of Jackson API. For a long time, I only knew that Jackson can be used to parse JSON but later realized that you can also use it to parse or read CSV file in Java. The Jackson DataFormat CSV library allows you to read a CSV file in just a couple of line and its really powerful and feature rich. For example, you can read a CSV file with a header or without a header. You can even read a tab-delimited text file like CSV. It's also highly configurable and allows you to define columns separator to read a text file with any delimiter. You can even use it to directly convert the CSV data into Java objects, just like we do while reading JSON String in Java.

For a long time, I was like DIY guy i.e. I would like to code everything I need and that's why I always have that big Utility class in my every Java project but things changed after reading the Effective Java.

The book is full of best practices and great practical advice from Joshua Bloch, author of Java Collection framework and many key classes on the java.lang package. In one of the items on Effective Java, he advised that you should always use libraries for the common task instead of re-inventing the wheel and from then I have not looked back.

Same is true for reading or parsing CSV file in Java. If you look at my earlier solution, it wasn't a production ready solution. I have demonstrated how you can use BufferedReader to read a CSV file but it doesn't handle many corner cases like carriage return in values, any field protected by quotes, etc. It was also not optimized for performance.

When you use a tried and tested and proven library you get all these benefits by default and that's the main reason I ask Java developers to get themselves familiar with essential and useful Java libraries. I have shared around 20 most useful Java libraries earlier and I am encouraging my readers to suggest as well, if you haven't read that article yet, you should read it now.




How to parse a CSV file with column header in Java using Jackson

Anyway, let's come back to the topic. In this article, I'll show you how to read a CSV file using the Jackson library in Java.

Suppose we have following CSV file which contains the title, author, and price of popular online courses for Java developers.

Title,Author,Price
REST With Spring,Eugen Paraschiv, 290
Learn Spring Security,Baeldung,290
Complete Java MasterClass,Udemy,200

Actually, I was tired with the book examples I always use, so, I used online courses this time, but they are some of the really best courses and if you are interested in Java then The Complete Java Masterclass is one of the best course to start with, feel free to join them.

How to read a CSV file in Java using Jackson with Example


Now, to represent this data in our Java application, I have created a class called OnlineCourse, which looks like below:

class OnlineCourse{
  private String title;
  private String author;
  private int price; 
 
  ...
 
  public OnlineCourse(){
     // no argument constructor required by Jackson
  }
 
}

I have omitted other constructors, getter, and setter for readability and you can also do if you use the Lombok library. It has both pros and cons but that's a topic for another day.

Just remember that Jackson use reflection hence a default no-argument constructor is mandatory in your class.

Now, we'll write code to read this CSV file in Java and copy the objects into ArrayList or just print them into the console.


This is what you need to read the CSV file using Jackson:

CsvMapper csvMapper = new CsvMapper();
CsvSchema schema = CsvSchema.emptySchema().withHeader(); 
 
ObjectReader oReader = csvMapper.reader(OnlineCourse.class).with(schema);
try (Reader reader = new FileReader("file.txt")) {
    MappingIterator<OnlineCourse> mi = oReader.readValues(reader);
    while (mi.hasNext()) {
      System.out.println(current);
    }
}

A CsvMapper is a class which maps data from CSV to Java objects while CsvSchema defines Schema like whether CSV has a header or not. You can also specify if a file is comma separated or tab delimited, which we'll see in the next article.

This will print following in the console:

EBook [title=REST With Spring, author=Eugen Paraschiv, price=290]
EBook [title=Learn Spring Security, author=Baeldung, price=290]
EBook [title=Complete Java MasterClass, author=Udemy, price=200

Which means our program is successfully read the CSV file. If you want you can store the objects into a List or Map as well as we'll do in our sample program. Btw, if you are not familiar with essential Collection classes like those then please see Java Fundamentals: Collections course by Richard Warburton on Pluralsight.

How to parse a CSV file with column header in Java using Jackson



Jackson Example to Read CSV File in Java 

You can configure Jackson to use the first line of CSV document to get the names (no types) for Schema. A schema object is required to ensure correct ordering of columns; schema instances are immutable and fully reusable (as are ObjectWriter instances).

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
 
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
 
/*
* Java Program to iterate over JSONObject of json-simple
*/
public class JacksonTest {
 
public static void main(String args[]) throws FileNotFoundException, IOException { 
    CsvMapper csvMapper = new CsvMapper();
    CsvSchema schema = CsvSchema.emptySchema().withHeader(); 
 
    ObjectReader oReader = csvMapper.reader(OnlineCourse.class).with(schema);
    List<OnlineCourse> courses = new ArrayList<>();
 
     try (Reader reader = new FileReader("file.txt")) {
           MappingIterator<OnlineCourse> mi = oReader.readValues(reader);
           while (mi.hasNext()) {
                 OnlineCourse current = mi.next();
                 courses.add(current);
                 System.out.println(current);
      }
}
 
   System.out.println("number of courses into list: " + courses.size());
 
}
 
}
 
 
class OnlineCourse{
private String title;
private String author;
private int price; 
 
public OnlineCourse(){
    // no argument constructor required by Jackson
}
 
public OnlineCourse(String title, String author, int price) {
    this.title = title;
    this.author = author;
     this.price = price;
}
 
public String getTitle() {
    return title;
}
 
public String getAuthor() {
   return author;
}
 
public int getPrice() {
   return price;
}
 
 
public void setTitle(String title) {
   this.title = title;
}
 
public void setAuthor(String author) {
   this.author = author;
}
 
public void setPrice(int price) {
   this.price = price;
}
 
 
@Override
public String toString() {
     return "EBook [title=" + title + ", author=" + author + ", price="
                              + price + "]";
  } 
 
}
 
Output:
EBook [title=REST With Spring, author=Eugen Paraschiv, price=290]
EBook [title=Learn Spring Security, author=Baeldung, price=290]
EBook [title=Complete Java MasterClass, author=Udemy, price=200]
number of courses into list: 3

You can see that we have successfully converted a CSV file into a bunch of Java object. Each line which is nothing but a CSV String now represents a Java object. If you want to learn more about Jackson, I suggest you take a look at the JSON with Java APIs and REST Web Services course on Udemy.

JSON with Java APIs and REST Web Services course udemy



Common Errors

Nothing is easy in this world and if you do something the first time, you are bound to get some obstacles and that's true with parsing a CSV file using Jackson as well.

Exception in thread "main" java.lang.VerifyError: Cannot inherit from final class
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at com.fasterxml.jackson.dataformat.csv.CsvMapper.<init>(CsvMapper.java:39)
at JacksonTest.main(JacksonTest.java:25)


Cause and Solution

This error puzzled me a little bit but I quickly realize that it has something to do with incompatible versions because an error is coming from the Jackson library itself. That was indeed the case, I was using jackson-dataformat-csv-2.9.jar but I had jackson-core-2.2.3.jar in my classpath. After using jackson-dataformat-csv-2.2.jar the error goes away automatically.

In short, make sure that all your Jackson components have the same minor version: with dataformat-csv 2.9.jar you MUST use jackson-core and jackson-databind of 2.9 as well.

Btw, it's better to use tools like Maven or Gradle which will do dependency management for you, instead of you downloading Jackson JAR manually.




Another error:
at [Source: java.io.FileReader@3b81a1bc; line: 2, column: 16] (through reference chain: OnlineCourse["Title"])
at com.fasterxml.jackson.databind.MappingIterator.next(MappingIterator.java:122)
at JacksonTest.main(JacksonTest.java:34)
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "Title" (class OnlineCourse), not marked as ignorable (3 known properties: , "title", "price", "author"])
at [Source: java.io.FileReader@3b81a1bc; line: 2, column: 16] (through reference chain: OnlineCourse["Title"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:79)
at com.fasterxml.jackson.databind.DeserializationContext.reportUnknownProperty(DeserializationContext.java:555)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:708)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1160)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:315)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
at com.fasterxml.jackson.databind.MappingIterator.nextValue(MappingIterator.java:189)
at com.fasterxml.jackson.databind.MappingIterator.next(MappingIterator.java:120)
... 1 more


Reason:
When you parse CSV data using Jackson it's like parsing JSON which means your property should exactly match with the fields in your class. It's also case-sensitive. In our case, the field in the class is called "title" while in the CSV file header is called "Title" hence error, after sorting that this error has gone.


That's all about how to read a CSV file in Java using Jackson DataFormat CSV API. You can easy it's very easy to that. The Jackson library is both powerful and feature-rich and allows you to configure CSVSchema in multiple ways which means you can read CSV file with header (first line), without header, values with quotes in it, and line break on values.

You can even read a tab-delimited text file using this library. I'll share some more examples of Jackson DataFormat CSV library but till then do whatever you want to do but don't trouble your mother :-)

Further Learning 


Other JSON tutorials for Java programmers
  • 3 ways to convert String to JSON object in Java? (tutorial)
  • 5 JSON libraries Java JEE Programmer should know (list)
  • Why use Spring to create REST API in Java? (article)
  • How to parse JSON with date field in Java using Jackson? (tutorial)
  • How to convert JSON array to String array in Java using Gson? (tutorial)
  • 6 Courses to learn Spring in depth (courses)
  • How to Escape JSON String in Eclipse (tips)
  • How to ignore Unknown properties while parsing JSON in Java? (tutorial)
  • How to download the Jackson library for JSON parsing? (tutorial)
  • How to convert JSON Array to String Array in Java? (tutorial)
  • How to parse a large JSON file using Jackson Streaming API? (example)
  • How to use Google Protocol Buffer (protobuf) in Java? (tutorial)
  • Top 5 courses to learn Spring boot in depth (courses)
  • Top 10 RESTful Web Service Interview Questions (see here)
  • What is the purpose of different HTTP methods in REST? (see here)
  • 5 Courses to learn RESTFul Web Services in Java? (courses)

Thanks for reading this article so far. If you like this Jackson tutorial to parse CSV file in Java then please share with your friends and colleagues. If you have any questions or feedback then please drop a note. 

P. S. - If you are new to Java and looking for some free courses to start with then you can also check out this list of free Java Courses for Beginners. Join them before they expire.

No comments:

Post a Comment