Monday, June 25, 2018

How to parse JSON with date field in Java - Jackson @JsonDeserialize Annotation Example

I have read many articles on parsing JSON in Java and most of them give examples where properties are either String or int, there are very few examples, where you will see the JSON string contains a date field and that's one important thing to learn. It's easy to parse JSON in Java using Jackson or Gson with just integer and string field but you need to do a little more work if your JSON contains a date field because everything in JSON is String but Java is a type based programming language, where Date is a type.

You have proper classes e.g. java.util.Date or java.time.LocalDate to represent a Date in Java. When you use String to represent a Date, you have to format it into a specific format e.g. dd-MM-yyyy or yyyy-MM-dd and that's why when you parse or serialize a JSON with a date field, you need to use a custom deserializer to correctly parse the date contained in JSON string properties.

Jackson allows you to do that using @JsonDeserialize annotation. You can annotate a field with this annotation along with the class which Jackson should use to deserialized this field. This is a nice way to provide a class which can correctly format String to date.

For example, you have following JSON which reprsent the Effective Java 3rd Edtion book. We have a date field, publicationDate as 27th December, "2017-12-27.
{
  "title" : "Effective Java",
  "author" : "Joshua Bloch",
  "price" : 37,
  "publicationDate" : "2017-12-27"
}

How do we parse this JSON to create an equivalent Book or EBook object in Java? let's learn that see in this tutorial.



How to deserialize Date from JSON using Jackson

In order to correct deserialize a Date field, you need to do two things:

1) Create a custom deserializer by extending StdDeserializer<T> class and override its deserialize(JsonParser jsonparser, DeserializationContext context) method. This method should return a Date if we are using this to parse a date field in JSON.

If your date String is in "yyyy-dd-MM", here is how your implementation of StdDeserializer should look like:

How to parse JSON with date field in Java - Jackson @JsonDeserialize Annotation Example

You can get the value of date field as String by calling the getText() method of JsonParser class and then you can simply convert it into a Date object by using parse() method of SimpleDateFormat, as you normally parse Date in Java.

If you are using Java 8 then you can even use the java.time.LocalDate to represent a date and DateTimeFormatter to format/parse dates instead of using SimpleDateFormat class.

If you are not familiar with Java 8 then see Complete Java Masterclass course on Udemy to learn more about new Date and Time API in Java 8.

2) Next step is to annotate the actual date field in your POJO class using the @JsonDeserialize class as @JsonDeserialize(using = DateHandler.class) as shown below:

class EBook {
  private String title;
  private String author;
  private int price;

  @JsonDeserialize(using = DateHandler.class)
  private Date publicationDate;
  
  //.. details omitted
}

Now, when you parse the JSON String with a date field using ObjectMapper. readValue() method then it will use this DateHandler class to deserialize the date field i.e. publicationDate in our case. Let's see a live example now:



How to deserialize JSON with Date field in Java

Here is our complete Java program to parse a JSON with a date attribute in Java using Jackson API. As I said, we have created a custom DateHandler class to convert the string date field into actual Date object while parsing.

We had just created a DateHandler class and annotated the publicationDate property on EBook object with @JsonDeserialize annotation.

This is enough for Jackson to correctly handle dates in JSON String.

The JSON is contained in the final variable called "json" and I have used my Eclipse tricks to automatically escape JSON while pasting on String variable, instead of manually putting those forward slash and double quotes.

It really helps, especially when you quickly want to parse a JSON for testing or debugging purpose.  Btw, if you are new to Eclipse IDE, then I suggest you check Beginners Eclipse Java IDE Training Course, a great course to start with Eclipse.

mport java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;

/*
 * Java Program to parse JSON with date attribute using Jackson
 */
public class JacksonTest {

  private static String json = "{\r\n" + "\"title\" : \"Effective Java\",\r\n"
      + "\"author\" : \"Joshua Bloch\",\r\n" + "\"price\" : 37,\r\n"
      + "\"publicationDate\" : \"2017-12-27\"\r\n" + "}";

  public static void main(String args[]) throws IOException {

    // let's parse JSON with a date field
    ObjectMapper mapper = new ObjectMapper();
    EBook effectiveJava = mapper.readValue(json, EBook.class);
    System.out.println("Input json string");
    System.out.println(json);
    System.out.println("Generated java class: ");
    System.out.println(effectiveJava);

  }

}

/**
 * POJO or DTO class
 * @author WINDOWS 8
 *
 */
class EBook {
  private String title;
  private String author;
  private int price;
  @JsonDeserialize(using = DateHandler.class)
  private Date publicationDate;

  public EBook() {

  }

  public EBook(String title, String author, int price, Date publicationDate) {
    super();
    this.title = title;
    this.author = author;
    this.price = price;
    this.publicationDate = publicationDate;
  }

  public String getTitle() {
    return title;
  }

  public String getAuthor() {
    return author;
  }

  public int getPrice() {
    return price;
  }

  public Date getPublicationDate() {
    return publicationDate;
  }

  public void setTitle(String title) {
    this.title = title;
  }

  public void setAuthor(String author) {
    this.author = author;
  }

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

  public void setPublicationDate(Date publicationDate) {
    this.publicationDate = publicationDate;
  }

  @Override
  public String toString() {
    return "EBook [title=" + title + ", author=" + author + ", price=" + price
        + ", publicationDate=" + publicationDate + "]";
  }

}

/**
 * Custom Date DeSerializer for JSON
 * @author WINDOWS 8
 *
 */
class DateHandler extends StdDeserializer<Date> {

  public DateHandler() {
    this(null);
  }

  public DateHandler(Class<?> clazz) {
    super(clazz);
  }

  @Override
  public Date deserialize(JsonParser jsonparser, DeserializationContext context)
      throws IOException {
    String date = jsonparser.getText();
    try {
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
      return sdf.parse(date);
    } catch (Exception e) {
      return null;
    }
  }

}
Output:
input json string
{
"title" : "Effective Java",
"author" : "Joshua Bloch",
"price" : 37,
"publicationDate" : "2017-12-27"
}
generated java class: 
EBook [title=Effective Java, author=Joshua Bloch, price=37, 
publicationDate=Wed Dec 27 00:00:00 PST 2017]

You can see that the Date field in the Java class i.e. publicationDate is correctly populated from the JSON String publicationDate attribute, "publicationDate" : "2017-12-27".


That's all about how to deal with a JSON string with date field in Java. As you see, we can easily parse that using Jackson API. It's really rich and powerful. It provides annotations to hook a custom deserializer for any field and that works like a charm in case of parsing a JSON with date field in it.

Though, you should remember that this solution will only work in case of deserializing data because we only wrote a custom deserializer. If you have to generate JSON using a Java object with Date field then we also need to write a custom serializer. I'll explain that in next article, but if you can't wait, just check JSON with Java APIs on Udemy to learn Jackson API in depth.


Other JSON tutorials in Java you may like
JSON in Action: Build JSON-Based Applications 
How to parse JSON using Gson?
5 JSON parsing libraries Java Developers Should Know
How to parse JSON array in Java?
How to convert JSON to HashMap in Java?
10 Things Java developer should learn in 2018
How to ignore unknown properties while parsing JSON in Java?

Thanks for reading this article so far. If you like this Java JSON tutorial using Jackson API then please share with your friends and colleagues. If you have any questions or feedback then please drop a note. 

2 comments :

Nino Argento said...

Isn't it just better to pass a long as time in milliseconds and make the conversion at the receiver end?

Anonymous said...

I have a scenario like as follows:-
i need to send data with multiple lines to POST API but i keep getting this error when parsing it :
json parse exception :Illegal unquoted character ((CTRL-CHAR, code 10))

can u guide me how to fix this issue ?

Post a Comment