I am new to Spring Data REST project and I am trying to create my first RESTful service. The task is simple, but I am stuck.
I want to perform CRUD operations on a user data stored in an embedded database using RESTful API.
But I cannot figure out how to make the Spring framework process the birthData as "1999-12-15" and store it as a LocalDate. The @JsonFormat annotation does not help.
At present I get the error:
HTTP/1.1 400 Content-Type: application/hal+json;charset=UTF-8 Transfer-Encoding: chunked Date: Thu, 24 Aug 2017 13:36:51 GMT Connection: close {"cause":{"cause":null,"message":"Can not construct instance of java.time.LocalDate: no String-argument constructor/factory method to deserialize from String value ('1999-10-10')\n at [Source: org.apache.catalina.connector.CoyoteInputStream@4ee2a60e; line: 1, column: 65] (through reference chain: ru.zavanton.entities.User[\"birthDate\"])"}, "message":"JSON parse error: Can not construct instance of java.time.LocalDate: no String-argument constructor/factory method to deserialize from String value ('1999-10-10'); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of java.time.LocalDate: no String-argument constructor/factory method to deserialize from String value ('1999-10-10')\n at [Source: org.apache.catalina.connector.CoyoteInputStream@4ee2a60e; line: 1, column: 65] (through reference chain: ru.zavanton.entities.User[\"birthDate\"])"}
How to make it work, so that client calls like:
curl -i -X POST -H "Content-Type:application/json" -d "{ \"firstName\" : \"John\", \"lastName\" : \"Johnson\", \"birthDate\" : \"1999-10-10\", \"email\" : \"[email protected]\" }" http://localhost:8080/users
will actually store the entity into the database.
Below is the information about the classes.
The user class:
package ru.zavanton.entities; import com.fasterxml.jackson.annotation.JsonFormat; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import java.time.LocalDate; @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; private String firstName; private String lastName; @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") private LocalDate birthDate; private String email; private String password; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public LocalDate getBirthDate() { return birthDate; } public void setBirthDate(LocalDate birthDate) { this.birthDate = birthDate; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
The UserRepository class:
package ru.zavanton.repositories; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.query.Param; import org.springframework.data.rest.core.annotation.RepositoryRestResource; import ru.zavanton.entities.User; @RepositoryRestResource(collectionResourceRel = "users", path = "users") public interface UserRepository extends PagingAndSortingRepository<User, Long> { User findByEmail(@Param("email") String email); }
Application class:
package ru.zavanton; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
You need jackson dependency for this serialization and deserialization.
Add this dependency:
Gradle:
compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.4")
Maven:
<dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> </dependency>
After that, You need to tell Jackson ObjectMapper to use JavaTimeModule. To do that, Autowire ObjectMapper in the main class and register JavaTimeModule to it.
import javax.annotation.PostConstruct; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; @SpringBootApplication public class MockEmployeeApplication { @Autowired private ObjectMapper objectMapper; public static void main(String[] args) { SpringApplication.run(MockEmployeeApplication.class, args); } @PostConstruct public void setUp() { objectMapper.registerModule(new JavaTimeModule()); } }
After that, Your LocalDate and LocalDateTime should be serialized and deserialized correctly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With