This article is about fixing Deserialization fails depending on the order of deserialized objects with Cannot construct instance (although at least one Creator exists) in FasterXML jackson-databind
  • 06-Feb-2023
Lightrun Team
Author Lightrun Team
Share
This article is about fixing Deserialization fails depending on the order of deserialized objects with Cannot construct instance (although at least one Creator exists) in FasterXML jackson-databind

Deserialization fails depending on the order of deserialized objects with “Cannot construct instance (although at least one Creator exists)” in FasterXML jackson-databind

Lightrun Team
Lightrun Team
06-Feb-2023

Explanation of the problem

The deserialization of class ContainerTwo is broken if class ContainerOne is deserialized before it. Both classes are immutable and use @JsonCreator and property-based constructors, with all properties annotated with @JsonProperty. This issue appears to be caused by some sort of caching error, where the property-based creator is ignored during the second invocation. The issue has been reproduced in version 2.12.3 and 2.13.0.

To reproduce the issue, a minimal setup is provided that uses Jackson’s ObjectMapper to deserialize JSON strings into objects of type ContainerOne and ContainerTwo. The exception thrown during the deserialization of ContainerTwo is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of ‘com.dinopraso.serialization.json.Common’ (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator).

Removing the @JsonIgnoreProperties(“twos”) annotation from the getter in ContainerTwo or making Common mutable by adding setters are two potential solutions, but are not feasible options at this time. The expected behavior is that both objects should be deserialized regardless of their invocation order.

Troubleshooting with the Lightrun Developer Observability Platform

Getting a sense of what’s actually happening inside a live application is a frustrating experience, one that relies mostly on querying and observing whatever logs were written during development.
Lightrun is a Developer Observability Platform, allowing developers to add telemetry to live applications in real-time, on-demand, and right from the IDE.

  • Instantly add logs to, set metrics in, and take snapshots of live applications
  • Insights delivered straight to your IDE or CLI
  • Works where you do: dev, QA, staging, CI/CD, and production

Start for free today

Problem solution for Deserialization fails depending on the order of deserialized objects with “Cannot construct instance (although at least one Creator exists)” in FasterXML jackson-databind

The issue of deserialization failing in FasterXML jackson-databind with the error “Cannot construct instance (although at least one Creator exists)” can occur when the objects being deserialized have circular references. To solve this issue, you can use one of the following solutions:

  1. Use JsonIdentityInfo: You can use the @JsonIdentityInfo annotation to specify a serialization ID for objects that have circular references.
  2. Use JsonManagedReference and JsonBackReference: You can use the @JsonManagedReference and @JsonBackReference annotations to specify the direction of the reference. The @JsonManagedReference annotation should be placed on the parent object and the @JsonBackReference annotation should be placed on the child object.
  3. Use custom serialization and deserialization: You can write custom serialization and deserialization code to handle circular references.
  4. Use a DTO (Data Transfer Object) pattern: You can use a DTO pattern to separate the data structure from the object graph, avoiding circular references.

It is recommended to use the first solution, as it is the most straightforward and easy to implement.

Other popular problems with jackson-databind

Problem: Unrecognized field, not marked as ignorable error

This error occurs when Jackson encounters a field in the JSON data that does not have a corresponding property in the target class.

Solution:

To solve this problem, you can either add the missing property to the target class or annotate the class with @JsonIgnoreProperties to ignore unrecognized fields.

Here’s an example of a target class with @JsonIgnoreProperties:

@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
    private String name;
    private int age;

    // constructor, setters, and getters
}

Problem: Serialization fails with StackOverflowError

This error occurs when there is a circular reference in the object graph during serialization. This means that an object references itself, either directly or indirectly.

Solution:

To solve this problem, you can annotate the object with @JsonIdentityInfo to specify a unique identifier for each instance of the object.

Here’s an example of a target class with @JsonIdentityInfo:

@JsonIdentityInfo(
    generator = ObjectIdGenerators.IntSequenceGenerator.class, 
    property = "@id")
public class User {
    private String name;
    private int age;
    private User friend;

    // constructor, setters, and getters
}

In the above example, the @JsonIdentityInfo annotation specifies that the @id property should be used as the unique identifier for each instance of the User class. The ObjectIdGenerators.IntSequenceGenerator generator generates a sequence of integers as the identifier.

Problem: Handling polymorphic types, particularly when serializing and deserializing subtypes of a common base class

The issue arises when a common base class has multiple subtypes and during serialization the type information of the subtype is lost. During deserialization, Jackson doesn’t know which concrete type to instantiate based on the serialized JSON data.

Solution:

To solve this problem, you can use Jackson’s @JsonTypeInfo and @JsonSubTypes annotations. @JsonTypeInfo is used to specify how type information is included in the serialized JSON data and @JsonSubTypes is used to specify the subtypes of a common base class.

Here’s an example to demonstrate this solution:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
        @JsonSubTypes.Type(value = ConcreteType1.class, name = "type1"),
        @JsonSubTypes.Type(value = ConcreteType2.class, name = "type2")
})
abstract class BaseClass {
    // common fields
}

class ConcreteType1 extends BaseClass {
    // specific fields
}

class ConcreteType2 extends BaseClass {
    // specific fields
}

With these annotations in place, during serialization, the type information of the subtype will be included in the serialized JSON data and during deserialization, Jackson will use the type information to instantiate the correct concrete type.

A brief introduction to jackson-databind

FasterXML jackson-databind is a widely used library for data serialization and deserialization in Java. It is a core component of the Jackson project and provides a flexible and efficient way to convert Java objects to and from JSON format. The library provides various functionality for data binding, including annotated POJOs, generics, and collections, among others. This makes it easier for developers to manage JSON data and handle it efficiently in their applications.

FasterXML jackson-databind supports a wide range of data types and supports customizable serialization and deserialization. This means that the library can be configured to handle data in a specific way and to handle various edge cases. The library also provides various performance optimizations such as caching, lazy loading, and data streaming, making it a fast and efficient option for managing JSON data in Java applications. In addition, FasterXML jackson-databind is highly customizable and extensible, allowing developers to add custom serialization and deserialization logic, and to modify the way the library handles specific data types.

Most popular use cases for jackson-databind

  1. Data serialization and deserialization: FasterXML jackson-databind is primarily used for data serialization and deserialization, which involves converting complex data structures like Java objects into a more compact and portable format like JSON or XML, and vice versa. This allows data to be exchanged between different systems and applications. The following code demonstrates how to serialize a Java object into a JSON string using FasterXML jackson-databind:
ObjectMapper mapper = new ObjectMapper();
MyObject object = ...;
String jsonString = mapper.writeValueAsString(object);
  1. JSON processing: FasterXML jackson-databind provides various features for processing JSON data, including stream processing, tree model representation, and custom serialization/deserialization. This makes it a powerful tool for dealing with JSON data in a Java environment.
  2. Integration with other technologies: FasterXML jackson-databind can be easily integrated with other Java technologies and frameworks, such as spring framework, jersey, etc. This makes it a versatile tool that can be used in a wide range of applications, from web services to mobile applications. The following code demonstrates how to deserialize a JSON string into a Java object using FasterXML jackson-databind in a Spring MVC application:
@RestController
public class MyController {
    @PostMapping("/my-endpoint")
    public MyObject myEndpoint(@RequestBody MyObject object) {
        // Do something with the object
        return object;
    }
}
Share

It’s Really not that Complicated.

You can actually understand what’s going on inside your live applications.

Try Lightrun’s Playground

Lets Talk!

Looking for more information about Lightrun and debugging?
We’d love to hear from you!
Drop us a line and we’ll get back to you shortly.

By submitting this form, I agree to Lightrun’s Privacy Policy and Terms of Use.