How to Solve UnrecognizedPropertyException: Unrecognized field, not marked as ignorable
阿新 • • 發佈:2018-12-29
While parsing JSON string received from one of our RESTful web services, I was getting this error "Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "person" (class Hello$Person), not marked as ignorable". After some research, I found that this is one of the common error while parsing JSON document using Jackson open source library in Java application. The error messages say that it is not able to find a suitable property name called "person" in our case, let's first take a look at the JSON we are trying to parse, the class we are using to represent the JSON document and the error message itself.
Error Message:
Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "person" (class Hello$Person), not marked as ignorable (4 known properties: , "id", "city", "name", "phone"])
The error messages say that it can find out id, city, name and phone attributes in the Person class but not able to locate the "person" field.
Our POJO class looks like below:
class Person{
private int id;
private String name;
private String city;
private long phone;
.....
}
and the JSON String:
{
"person": [
{
"id": "11",
"name": "John",
"city": "NewYork",
"phone": 7647388372
}
]
}
If you look carefully, the "person" field points to a JSON array and not object, which means it cannot be mapped to person class directly.
How to solve this problem
Here are steps to solve this problem and get rid of this errorr: 1) Configure Jackson's ObjectMapper to not fail when encounger unknown properties You can do this by disabling DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES property of ObjectMapper as shown below: // Jackson code to convert JSON String to Java object ObjectMapper objectMapper = new ObjectMapper(); objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); Person p = objectMapper.readValue(JSON, Person.class); System.out.println(p); Now, the error will go away but the Output is not what you expected, it will print following: Person [id=0, name=null, city=null, phone=0] You can see that Person class is not created properly, the relevant attributes are null even though the JSON String contains its value. The reason was that JSON String contains a JSON array, the person field is pointing towards an array and there is no field corresponding to that in Person class. In order to properly parse the JSON String we need to create a wrapper class Community which will have an attribute to keep an array of Person as shown below:static class Community { private List<Person> person; public List<Person> getPerson() { return person; } public void setPerson(List<Person> person) { this.person = person; } }Now, we will convert the JSON String to this Community class and print each person from the list as shown below: ObjectMapper objectMapper = new ObjectMapper(); //objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); Community c = objectMapper.readValue(JSON, Community.class); for (Person p : c.getPerson()) { System.out.println(p); } This will print the details of a person properly as shown below: Person [id=11, name=John, city=NewYork, phone=7647388372] Now, coming back to a more general situation where a new field is added on JSON but not available in your Person class, let's see what happens. Suppose, our JSON String to parse is following: { "person": [ { "id": "11", "name": "John", "city": "NewYork", "phone": 7647388372, "facebook": "JohnTheGreat" } ] } When you run the same program with this JSON String, you will get following error: Again, Jackson is not able to recognize the new "facebook" property. Now, we can ignore this property by disabling the feature which tells Jackson to fail on the unknown property as shown below: ObjectMapper objectMapper = new ObjectMapper(); objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); Community c = objectMapper.readValue(JSON, Community.class); And this will print the person class properly as shown below: Person [id=11, name=John, city=NewYork, phone=7647388372] Alternatively, you can also use @JsonIgnoreProperties annotation to ignore undeclared properties. The @JsonIgnoreProperties is a class-level annotation in Jackson and it will ignore every property you haven't defined in your POJO. Very useful when you are just looking for a couple of properties in the JSON and don't want to write the whole mapping. This annotation provides control at class level i.e. you can tell Jackson that for this class, please ignore any attribute not defined by doing @JsonIgnoreProperties(ignoreUnknown = true) So, our Person class now looks like: @JsonIgnoreProperties(ignoreUnknown = true) static class Person{ private int id; private String name; private String city; private long phone; ...... } Sample program
import java.io.IOException; import java.util.List; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; /* * { "person": [ { "id": "11", "name": "John", "city": "NewYork", "phone": 7647388372 } ] } */ public class Hello { private static String JSON = "{\r\n" + " \"person\": [\r\n" + " {\r\n" + " \"id\": \"11\",\r\n" + " \"name\": \"John\",\r\n" + " \"city\": \"NewYork\",\r\n" + " \"phone\": 7647388372,\r\n" + " \"facebook\": \"JohnTheGreat\"\r\n" + " }\r\n" + " ]\r\n" + " } "; public static void main(String args[]) throws JsonParseException, JsonMappingException, IOException { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); Community c = objectMapper.readValue(JSON, Community.class); for (Person p : c.getPerson()) { System.out.println(p); } } static class Community { private List<Person> person; public List<Person> getPerson() { return person; } public void setPerson(List<Person> person) { this.person = person; } } static class Person { private int id; private String name; private String city; private long phone; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public long getPhone() { return phone; } public void setPhone(long phone) { this.phone = phone; } @Override public String toString() { return "Person [id=" + id + ", name=" + name + ", city=" + city + ", phone=" + phone + "]"; } } }When I run first version of this program, I was greeted with the following error: Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class Hello$Person]: can not instantiate from JSON object (need to add/enable type information?) at [Source: [email protected]; line: 2, column: 3] at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164) at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:984) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:276) 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 Hello.main(Hello.java:40) This error was occurring because my nested class Person was not static, which means it cannot be instantiated because having any Outer class instance. The issue resolved after making the Person class static. If you are not familiar with this detail before, I suggest you check Java Fundamentals: The Core Platform, a free course from Pluralsight to learn more about such details of Java programming language. You can signup for a free trial, which gives you 10 days access, enough to learn whole Java for free. Now, let's see the real error: Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "person" (class Hello$Person), not marked as ignorable (4 known properties: , "id", "city", "name", "phone"]) at [Source: [email protected]; line: 2, column: 14] (through reference chain: Person["person"]) 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 Hello.main(Hello.java:40) When you run the final version of the program you will see following output: Person [id=11, name=John, city=NewYork, phone=7647388372] This means we are able to parse JSON containing unknown attributes successfully in Jackson.
How to compile and run this program?
You can simply copy paste the code into your favorite IDE e.g. Eclipse to compile and run the program. In Eclipse, you don't even need to create the class file because it will automatically create the class and package if you copy paste the code in Java project. If Eclipse is your primary IDE and you want to learn more of such productivity tips I suggest you check out The Eclipse Guided Tour - Part 1 and 2 By Tod Gentille. It's a free, online course to learn both basic and advanced feature of Eclipse IDE, which every Java developer should be aware of. You can get access to this course by signing up for a free trial, which gives you 10 days access to the whole Pluralsight library, one of the most valuable collection to learn about programming and other technology. Btw, 10 days is more than enough to learn Java and Eclipse together. Anyway, once you copy paste the code, all you need to do is either include Maven dependency in your pom.xml or manually download required JAR file for Jackson open source library. For Maven Users You can add following Maven dependency on your project's pom.xml and then run the mvn build or mvn install command to compile:<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.2.3</version> </dependency>