How to ignore unknown properties while parsing JSON in Java - Jackson @JsonIgnoreProperties Annotation Example

One of the common problem while parsing JSON in Java using Jackson API is that it fails when your JSON contains unknown properties i.e. your Java class doesn't have all the field corresponding to all JSON properties. For example, if you are consuming JSON from a REST Web Service and tomorrow they added a new field into JSON then your code will break because Jackson will throw UnrecognizedPropertyException and stop parsing JSON. This is troublesome and can cause problems in production if you are not aware. I  have faced this issue when a developer shipped the code to consume data from REST API without proper handling unknown fields.

The code worked fine for months but it broke as soon as source system added a new field is added to REST API. The developer chooses to ignore the update because we weren't interested in that field but he failed to foresee that it will impact the JSON parsing.

Anyway, it was our fault that we didn't review code properly and allowed him to release his code into production without handling unknown files. The issue could have simply been avoided if he was familiar with Jackson library in a little bit more detail.

Jackson API provides two ways to ignore unknown fields, first at the class level using @JsonIgnoreProperties annotation and second at the ObjectMapper level using configure() method.

You will see both approaches in this article and learn how to use them and when to use @JsonIgnoreProperties and when to ignore unknown fields in JSON globally at the ObjectMapper level.




Ignoring unknown properties using @JsonIgnoreProperties

If you are creating a Model class to represent the JSON in Java, then you can annotate the class with @JsonIgnoreProperties(ignoreUnknown = true) to ignore any unknown field. Which means if there is a new field is added tomorrow on JSON which represent your Model then Jackson will not throw UnrecognizedPropertyException while parsing JSON in Java. 

You can use this approach if you want to ignore unknown properties only for that Model class, but this is preferred approach because it provides you more control.

Let's see an example of using @JsonIgnoreProperties in Java:

Suppose I have following JSON, which represents my favorite book, Effective Java 3rd Edition, a must read books for every Java developer in 2018, and a Java model class in my project:

How to ignore unknown properties while parsing JSON in Java


If tomorrow, I add a new field called "edition" in the JSON then parsing of this JSON will fail with the UnrecognizedPropertyException error. Something like :

Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "edition" (class EBook), not marked as ignorable (3 known properties: , "title", "price", "author"])"

This means Jackson is not able to find any field in your EBook class for "edition" property in JSON and hence it's throwing the UnrecognizedPropertyException error.

You can solve this problem and prevent this error by using @JsonIgnoreProperties annotation as shown below:

@JsonIgnoreProperties(ignoreUnknown = true)
class EBook{
  private String title;
  private String author;
  private int price; 
  ..

}

We have just annotated a whole model class as @JsonIgnoreProperties(ignoreUnknown = true), which mean any unknown property in JSON String i.e. any property for which we don't have a corresponding field in the EBook class will be ignored. If you compile and run your program again it will work fine.

In Jackson 2.x, the @JsonIgnoreProperties reside in com.fasterxml.jackson.annotation package, hence you need to import it as :

import com.fasterxml.jackson.annotation.JsonIgnoreProperties.

If you are using an older version of Jackson API e.g. Jackson 1.x then this annotation belongs to a different package, beware of that, especially if you have both Jackson 1.x and Jackson 2.x in your classpath.



Ignoring Unknown Property in JSON Globally using Jackson

Another way to deal with unknown properties in JSON you are parsing is to configure ObjectMapper not to fail when it encounters an unknown property. This will also solve the problem of UnrecognizedPropertyException. You can enable this setting by calling configure() method as shown below:

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);


This will now ignore unknown properties for any JSON it's going to parse, You should only use this option if you can't annotate a class with @JsonIgnoreProperties annotation.

Btw, if you are not familiar with JSON parsing libraries in Java, then JSON with Java APIs, jQuery, and REST Web Services on Udemy is a good place to start with.

Jackson @JsonIgnoreProperties Annotation Example



Java Program to Ignore Unknown Properties while Parsing JSON using Jackson

Let's see whatever we have learned so far in action. Btw, if you are confused with my String JSON and a lot of "/r/n" string then don't worry. I haven't done that manually. I used this Eclipse trick to copy my JSON and it automatically included necessary escape characters. This is required because JSON string is enclosed with double quotes ("") which need to be escaped in Java.

Btw, if you are new to Eclipse IDE, then I suggest you check Beginners Eclipse Java IDE Training Course on Udemy to learn it well. It's important for Java developer to know their tools well, especially IDE so that they effectively develop, test, debug, and run their Java application.

import 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.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;

/*
 * Java Program to iterate over JSONObject of json-simple
 */
public class JacksonTest {

  private static String json = "{\r\n" + "\"title\" : \"Effective Java\",\r\n"
      + "\"author\" : \"Joshua Bloch\",\r\n" + "\"price\" : 37,\r\n"
      + "\"edition\" : 37\r\n" + "}";

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

    // let's parse JSON with a date field
    ObjectMapper mapper = new ObjectMapper();
    // mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
    // false);

    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);

  }

}

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

  public EBook() {
    // no argument constructor required by Jackson
  }

  public EBook(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:
Input json string
{
"title" : "Effective Java",
"author" : "Joshua Bloch",
"price" : 37,
"version" : 37
}
Generated java class: 
EBook [title=Effective Java, author=Joshua Bloch, price=37]

In this program, I have a JSON as discussed above which represent the Effective Java 3rd edition book, a must-read for every Java developer.

How to deal with unknown properties while parsing JSON in Java


I also have a model class called EBook, which is annotated with @JsonIgnoreProperties(ignoreUnknown = true) to ignore unknown properties.

If you look closely, our JSON String contains an "edition" property which is not defined in the Java class but the program works because we have marked EBook with

@JsonIgnoreProperties(ignoreUnknown = true) annotation.

If you want to test this program, then just remove that annotation and run the program, it will throw the following error.

Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field
 "edition" (class EBook), not marked as ignorable (3 known properties: , "title", "price", "author"])
at [Source: java.io.StringReader@19dfb72a; line: 5, column: 14] (through reference chain: EBook["edition"])
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.ObjectMapper._readMapAndClose(ObjectMapper.java:2888)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2034)
at JacksonTest.main(JacksonTest.java:30)

This happened because of "edition" field which is only present in JSON and not in the Java class. If you put the annotation back then the code will work again.

You can similarly test how to ignore unknown field at the object mapper level, instead of putting the @JsonIgnoreProperties annotation back, you just uncomment the mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) line in the code and run the program. This time also it will work because Jackson is ignoring all unknown properties.


That's all about how to ignore unknown properties while parsing JSON in Java using Jackson API. You can do this either by using @JsonIgnoreProperties annotation or configuring ObjectMapper to not fail when encountering unknown properties during deserialization by disabling FAIL_ON_UNKNOWN_PROPERTIES.

Though, the preferred approach is to ignore unknown properties at class level using @JsonIgnoreProperties(ignoreUnknown = true) and only do this on the ObjectMapper level if you can't annotate your class with this annotation i.e. you don't own the class. It's also a best practice to annotated your model class with @JsonIgnoreProperties to avoid the issue I have explained in the first paragraph.

Other Java and JSON resources 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
JSON with Java APIs, jQuery, and REST Web Services

Thanks for reading this article so far. If you like this article then please share with your friends and colleagues. If you have any questions or doubt, please drop a note.

No comments :

Post a Comment