Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot construct instance of `com.domain.User` (no Creators, like default constructor, exist): cannot deserialize from Object value

I have a controller that accepts ObjectNode as @RequestBody.

That ObjectNode represents json with some user data

{
    "given_name":"ana",
    "family_name": "fabry",
    "email": "[email protected]",
    "password": "mypass",
    "gender": "FEMALE"
}

Controller.java

@PostMapping(produces = MediaType.APPLICATION_JSON_VALUE)
    public JsonNode createUser(@RequestBody ObjectNode user){
        return userService.addUser(user);
 }

I want to get user as ObjectNode convert it to Java POJO save it to database and again return it as JsonNode.

UserServiceImpl.java

    private final UserRepository userRepository;
    private final UserMapper userMapper;

    @Override
    public JsonNode addUser(@RequestBody ObjectNode user) {
        try {
            return userMapper.fromJson(user)
                    .map(r -> {
                        final User created = userRepository.save(r);
                        return created;
                    })
                    .map(userMapper::toJson)
                    .orElseThrow(() -> new ResourceNotFoundException("Unable to find user"));
        } catch (RuntimeException re) {
            throw re;
        }
    }

To convert ObjectNode to POJO

I did this in my UserMapper class:

public Optional<User> fromJson(ObjectNode jsonUser) {
  User user = objectMapper.treeToValue(jsonUser, User.class);
}

Also, to write object to JsonNode I did this:

public JsonNode toJson(User user) {
        ObjectNode node = objectMapper.createObjectNode();
        node.put("email", user.email);
        node.put("password", user.password);
        node.put("firstName", user.firstName);
        node.put("lastName", user.firstName);
        node.put("gender", user.gender.value);
        node.put("registrationTime", user.registrationTime.toString());
        return node;
}

User.java

@Document(collection = "user")
@Builder
@AllArgsConstructor
public class User {

    @Indexed(unique = true)
    public final String email;
    @JsonProperty("password")
    public final String password;
    @JsonProperty("firstName")
    public final String firstName;
    @JsonProperty("lastName")
    public final String lastName;
    @JsonProperty("gender")
    public final Gender gender;
    @JsonProperty("registrationTime")
    public final Instant registrationTime;

    public static User createUser(
            String email,
            String password,
            String firstName,
            String lastName,
            Gender gender,
            Instant registrationTime){
        return new User(email, password, firstName, lastName, gender, registrationTime);
    }
}

When I run my application, this is the error I am receiving:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.domain.User` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

I have read about the error, and it seems this error occurs because Jackson library doesn't know how to create a model which doesn't have an empty constructor and the model contains a constructor with parameters which I annotated its parameters with @JsonProperty("fieldName"). But even after applying @JsonProperty("fieldName") I am still getting the same error.

I have defined ObjecatMapper as Bean

    @Bean
    ObjectMapper getObjectMapper(){
        return new ObjectMapper();
    }

What am I missing here?

like image 421
user9347049 Avatar asked Feb 27 '26 08:02

user9347049


2 Answers

I could reproduce the exception. Then I added an all-args constructor with each parameter annotated with the right @JsonProperty.

@JsonCreator
public User( 
    @JsonProperty("email") String email,
    @JsonProperty("password") String password,
    @JsonProperty("firstName") String firstName,
    @JsonProperty("lastName") String lastName,
    @JsonProperty("gender") String gender,
    @JsonProperty("registrationTime") Instant registrationTime){
            super();
            this.email = email;
            this.password = password;
            this.firstName = firstName;
            this.lastName = lastName;
            this.gender = gender;
            this.registrationTime = registrationTime;
}

Now, it creates the instance, but I get other mapping errors (Unrecognized field "given_name") which you should be able to resolve.

like image 120
Sree Kumar Avatar answered Feb 28 '26 23:02

Sree Kumar


Register Jackson ParameterNamesModule, which will automatically map JSON attributes to the corresponding constructor attributes and therefore will allow you to use immutable classes.

like image 43
Adam Siemion Avatar answered Feb 28 '26 22:02

Adam Siemion