If you're here, it's probably because you're attempting to deserialize a JSON object using Jackson in your Spring Boot application. And you get this error:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `Employee`

Or something similar.

Anyway, it's a pain.

Fortunately, the error message often goes on to tell you what's wrong.

And in this guide, I'll show you how to fix it.

No Default Constructor?

You might see this message along with the exception: no Creators, like default constructor, exist

But what the heck does that mean?

It means you've defined a constructor with one or more parameters. So you can't instantiate the class with an empty constructor.

And neither can Jackson.

Take a look at this code, for example:

public class Employee {

    private String id;    
    private String lastName;
    private String firstName;    
    
    public Employee(String lastName, String firstName) {
        this.lastName = lastName;
        this.firstName = firstName;
    }
...
}

That's pretty simple. It defines an Employee class with three fields: id, lastName, and firstName.

But it also defines a constructor that accepts two parameters: lastName and firstName.

Now if you want to instantiate the Employee class, you've got to do so with those two parameters, like this:

Employee employee = new Employee("Smith", "John");

But you can't do this:

Employee employee = new Employee();

The compiler will complain because there's no empty constructor defined.

What does all that have to do with Jackson? Quite a bit, actually.

Because Jackson can't instantiate the Employee class with an empty constructor, either. So it doesn't know what to do.

So if you try to deserialize this JSON object:

{
  "id" : "A17",
  "lastName" : "Smith",
  "firstName" : "Frank"
}

With this code:

ObjectMapper mapper = new ObjectMapper();  
Employee employee = mapper.readValue(json, Employee.class);

You'll get the aforementioned InvalidDefinitionException because Jackson can't instantiate the class with an empty constructor.

The Solution Is Simple

You've probably already guessed the solution by this point: just add an empty constructor!

Change the Employee class like so:

public class Employee {

    private String id;    
    private String lastName;
    private String firstName;    
    
    public Employee() {
    }
    
    public Employee(String lastName, String firstName) {
        this.lastName = lastName;
        this.firstName = firstName;
    }
...
}

Now rerun that deserialization code from above and everything should work out.

But is that the best solution?

Another Way

Chances are pretty good that if you created a class with a custom constructor it's because you don't want anyone instantiating the class with an empty constructor.

In that case, the solution above might not be your best bet.

Fortunately, you've got another option. Check this out:

public class Employee {

    private String id;    
    private String lastName;
    private String firstName;    
    
    @JsonCreator
    public Employee(@JsonProperty("lastName") String lastName, @JsonProperty("firstName") String firstName) {
        this.lastName = lastName;
        this.firstName = firstName;
    }
...
}

That @JsonCreator annotation tells Jackson to use that constructor when instantiating the class.

But you need more. You need to tell Jackson which parameters in the constructor match specific properties in the JSON object.

Hence the @JsonProperty annotations. So the "lastName" JSON property matches the lastName variable and the "firstName" JSON property matches the firstName variable.

That seems pretty intuitive to you and me, but you still gotta give Jackson that info.

Now rerun the deserialization code above and it's all good.

Wrapping It Up

Congratulations. You now know a couple of different ways to get rid of that InvalidDefinitionException problem.

Take what you've learned here and put it in your own applications. 

Have fun!