Jackson Exceptions – Problems and Solutions
1. Introduction
Table Of Contents
- 1. Introduction
- 2. InvalidDefinitionException: No Creators, like default constructor, exist
- 3. MismatchedInputException: Out of START_ARRAY token
- 4. InvalidDefinitionException: No properties discovered to create BeanSerializer
- 5. InvalidFormatException: Cannot deserialize value of type `int` from String
- 6. UnrecognizedPropertyException: Unrecognized field { }
- 7. MismatchedInputException: Root name { } does not match expected
- 8. JsonParseException: Unexpected character (code 39)
- 9. Summary
- 10. Download the source code
2. “InvalidDefinitionException: No Creators, like default constructor, exist”
2.1. Model
Consider the following model class Shop for deserialization operations for this example.
public class Shop { public int id; public String name; public Shop(int id, String name) { this.id = id; this.name = name;
2.2. Exception
private static void jacksonNoConstructor() { ObjectMapper mapper = new ObjectMapper(); String json = "{\"id\":1,\"name\":\"John\"}"; try { mapper.readValue(json, Shop.class); } catch (JsonProcessingException e) { System.out.println(e.getClass().getName() + " : " + e.getOriginalMessage());
An InvalidDefinitionException is thrown. The exception and the stack trace is:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `jackson.exceptions.Shop` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: .[Source: (String undefined)"{"id":1,"name":"John"}"; line: 1, column: 2] at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from( InvalidDefinitionException.java:67 undefined)
2.3. Problem
2.4. Solution
Provide a default constructor in the Shop class as shown below to fix this error.
public class Shop { public int id; public String name; public Shop(int id, String name) { this.id = id; this.name = name; public Shop() {
The deserialization after applying the fix will be successful without any exception at runtime.
3. MismatchedInputException: Out of START_ARRAY token
3.1. Model
Consider the following model class Customer with two fields id and name.
public class Customer { public int id; public String name;
3.2. Exception
private static void jacksonListToObject() { ObjectMapper mapper = new ObjectMapper(); String json = "[{\"id\":1,\"name\":\"John\"},{\"id\":2,\"name\":\"Adam\"}]"; try { mapper.readValue(json, Customer.class); } catch (JsonProcessingException e) { System.out.println(e.getClass().getName() + " : " + e.getOriginalMessage());
A MismatchedInputException is thrown. The exception and the stack trace is:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `jackson.exceptions.Customer` out of START_ARRAY token at [Source: (String)"[{"id":1,"name":"John"},{"id":2,"name":"Adam"}]"; line: 1, column: 1] at com.fasterxml.jackson.databind.exc. MismatchedInputException.from(MismatchedInputException.java:59)
3.3. Problem
3.4. Solution
private static void jacksonListToObjectFix() { ObjectMapper mapper = new ObjectMapper(); String json = "[{\"id\":1,\"name\":\"John\"}," + "{\"id\":2,\"name\":\"Adam\"}]"; try { List<Customer> customer = mapper.readValue (json, new TypeReference<List>() { System.out.println(customer); // Prints [Customer [id=1, name=John], // Customer [id=2, name=Adam]] } catch (JsonProcessingException e) { System.out.println(e.getClass().getName() + " : " + e.getOriginalMessage());
4. InvalidDefinitionException: No properties discovered to create BeanSerializer
4.1. Model
Consider the following model class Product.
public class Product { int id; String name; public Product(int id, String name) { this.id = id; this.name = name;
4.2. Exception
private static void privateFieldAndGetter() { ObjectMapper mapper = new ObjectMapper(); try { Product p = new Product(1, "Anmol"); mapper.writeValueAsString(p); } catch (JsonProcessingException e) { System.out.println(e.getClass().getName() + " : " + e.getOriginalMessage());
An InvalidDefinitionException is thrown. The exception and the stack trace is:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class jackson.exceptions.Product and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from (InvalidDefinitionException.java:77)
4.3. Problem
4.4. Solution
There are multiple solutions to fix this problem. Let’s discuss each of them with examples.
4.4.1. Modify The Model Class
public int getId() { return id; public String getName() { return name;
4.4.2. ObjectMapper setVisibility method
[Fix] ObjectMapper setVisibility
private static void privateFieldAndGetterFix() { ObjectMapper mapper = new ObjectMapper(); try { Product p = new Product(1, "Anmol"); mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY); String json = mapper.writeValueAsString(p); System.out.println(json); // Prints {"id":1,"name":"Anmol"} } catch (JsonProcessingException e) {
4.4.3. @JsonAutoDetect annotation
We can also use the
@JsonAutoDetect
annotation to fix this problem. For a detailed understanding of this annotation, check out the example on
Jackson Annotations
.
[Fix] @JsonAutoDetect
@JsonAutoDetect(fieldVisibility = Visibility.ANY) public class Product {.....}
5. InvalidFormatException: Cannot deserialize value of type `int` from String
5.1. Model
Consider the following model class Customer.
public class Customer { public int id; public String name;
5.2. Exception
private static void cannotDeserialize() { ObjectMapper mapper = new ObjectMapper(); String json = "{\"id\":\"Three\",\"name\":\"Anmol\"}"; try { mapper.readValue(json, Customer.class); } catch (JsonProcessingException e) { System.out.println(e.getClass().getName() + " : " + e.getOriginalMessage());
5.3. Problem
5.4. Solution
In such cases, there are two extreme solutions.
6. UnrecognizedPropertyException: Unrecognized field { }
6.1. Model
Consider the following model class Customer for this example.
public class Customer { public int id; public String name;
6.2. Exception
The following code attempts to deserialize a JSON string and throws an exception.
private static void unknownProperty() { ObjectMapper mapper = new ObjectMapper(); String json = "{\"id\":99,\"name\":\"Anmol\",\"location\":\"Bangalore\"}"; try { mapper.readValue(json, Customer.class); } catch (JsonProcessingException e) { System.out.println(e.getClass().getName() + " : " + e.getOriginalMessage());
6.3. Problem
6.4. Solution
This problem can be solved by using multiple approaches. Let’s discuss those.
6.4.1. The @JsonIgnore annotation
We can annotate our model class with
@JsonIgnoreProperties
and define a rule to ignore unknown properties. The below example shows this.
Customer.java [With Fix]
@JsonIgnoreProperties(ignoreUnknown = true) public class Customer { public int id; public String name;
6.4.2. The DeserializationFeature
We may also use the DeserializationFeature FAIL_ON_UNKNOWN_PROPERTIES and disable it on the ObjectMapper. This will cause deserialization not to fail on detecting unknown properties.
Deserialization [With Fix]
private static void unknownPropertyFix() { ObjectMapper mapper = new ObjectMapper(); String json = "{\"id\":99,\"name\":\"Anmol\",\"location\":\"Bangalore\"}"; mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); try { mapper.readValue(json, Customer.class); } catch (JsonProcessingException e) { System.out.println(e.getClass().getName() + " : " + e.getOriginalMessage()); e.printStackTrace();
The deserialization after applying the fix will be successful without any exception at runtime.
7. MismatchedInputException: Root name { } does not match expected
7.1. Model
Consider the following model class Customer for this example.
public class Customer { public int id; public String name;
7.2. Exception
private static void wrongJsonRoot() { ObjectMapper mapper = new ObjectMapper(); String json = "{\"jsonRoot\" : {\"id\":1,\"name\":\"John\"}}"; try { mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE); mapper.readValue(json, Customer.class); } catch (JsonProcessingException e) { System.out.println(e.getClass().getName() + " : " + e.getOriginalMessage());
A MismatchedInputException is thrown. The exception and the stack trace is:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Root name 'jsonRoot' does not match expected ('Customer') for type [simple type, class jackson.exceptions.Customer] at [Source: (String)"{"jsonRoot" : {"id":1,"name":"John"}}"; line: 1, column: 2] (through reference chain: jackson. exceptions.Customer["jsonRoot"]) at com.fasterxml.jackson.databind.exc.MismatchedInputException. from(MismatchedInputException.java:63)
7.3. Problem
7.4. Solution
@JsonRootName("jsonRoot") public class Customer { public int id; public String name;
private static void wrongJsonRootFix() { ObjectMapper mapper = new ObjectMapper(); String json = "{\"jsonRoot\" : {\"id\":1,\"name\":\"John\"}}"; try { mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE); Customer customer = mapper.readValue(json, Customer.class); System.out.println(customer.name + " - " + customer.id); // Print John - 1 } catch (JsonProcessingException e) { System.out.println(e.getClass().getName() + " : " + e.getOriginalMessage());
The above deserialization code will now execute without throwing any exception.
8. JsonParseException: Unexpected character (code 39)
8.1. Model
Consider the following model class Employee for this example.
public class Employee { public int id; public String name;
8.2. Exception
private static void code39Exception() { ObjectMapper mapper = new ObjectMapper(); String json = "{'id':99,'name':'Anmol'}"; try { mapper.readValue(json, Employee.class); } catch (JsonProcessingException e) { System.out.println(e.getClass().getName() + " : " + e.getOriginalMessage());
A JsonParseException is thrown. The exception and stack trace is:
com.fasterxml.jackson.core.JsonParseException: Unexpected character (''' (code 39)): was expecting double-quote to start field name at [Source: (String)"{'id':99,'name':'Anmol'}"; line: 1, column: 3] at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1851)
8.3. Problem
8.4. Solution
[Fix] A JsonFactory With Single Quotes enabled, supplied to ObjectMapper
private static void code39Fix() { String json = "{'id':99,'name':'Anmol'}"; try { JsonFactory jf = new JsonFactory(); jf.enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES); ObjectMapper mapper = new ObjectMapper(jf); Employee employee = mapper.readValue(json, Employee.class); System.out.println(employee.id + " = " + employee.name); // Prints 99 = Anmol } catch (JsonProcessingException e) { System.out.println(e.getClass().getName() + " : " + e.getOriginalMessage());
9. Summary
In this article, we spoke about Jackson Exceptions. Specifically, we explored some common exceptions that are encountered in programming with the Jackson API for serialization/deserialization. We did a deep dive into the causes of such exceptions and looked at the way to fix them.
10. Download the source code
You can download the full source code of this example here: Jackson Exceptions – Problems and Solutions