I have a controller that accepts ObjectNode
as @RequestBody
.
That ObjectNode
represents json
with some user data
{ "given_name":"ana", "family_name": "fabry", "email": "fabry@gmail.com", "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?
Advertisement
Answer
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.