Reputation: 587
Hey I've got the same problem as here: JSON Java 8 LocalDateTime format in Spring Boot I tried solutionts from there and it does not work. Could someone tell me what I did wrong?
I added
spring.jackson.serialization.write-dates-as-timestamps=false
to application.property My model class looks like this:
package bookrental.model.book;
import bookrental.model.account.User;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.util.ISO8601DateFormat;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.*;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.Date;
@Entity
@Getter
@Setter
@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor
public class BookRentals {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@OneToOne
private Book book;
@OneToOne
private User user;
@JsonFormat(pattern = ("yyyy/MM/dd HH:mm:ss"))
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime dateOfRental;
public BookRentals(Book book, User user) {
this.book = book;
this.user = user;
}
}
I set time like this:
private BookRentals prepareBookToRent(int userID, Book book) {
BookRentals bookRentals = new BookRentals(book, new User(userID));
bookRentals.setDateOfRental(LocalDateTime.now());
return bookRentals;
}
I added dependency:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.9.7</version>
</dependency>
And my JSON, looks like this:
[
{
"book": {
"author": "Henryk Sienkiewicz",
"category": "powieść historyczna",
"id": 1,
"title": "Krzyżacy"
},
"class": "bookrental.model.book.BookRentals",
"dateOfRental": {
"class": "java.time.LocalDateTime",
"dayOfMonth": 19,
"dayOfWeek": "WEDNESDAY",
"dayOfYear": 353,
"hour": 0,
"minute": 13,
"month": "DECEMBER",
"monthValue": 12,
"nano": 758649300,
"second": 8,
"year": 2018
},
"id": 1,
"user": {
"id": 2,
"name": "piotri",
"password": "123"
}
}
]
What else should I do?
I didn't try solutions with classes, because I dont know, where I should put them in what package. // EDIT After Erik's advice, pom.xml looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.book.rental.piotrek</groupId>
<artifactId>BookRental</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.22</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>net.sf.flexjson</groupId>
<artifactId>flexjson</artifactId>
<version>2.1</version>
</dependency>
</dependencies>
</project>
Upgrading didn't work. JSON:
[
{
"book": {
"author": "Henryk Sienkiewicz",
"category": "powieść historyczna",
"id": 1,
"title": "Krzyżacy"
},
"dateOfRental": {
"dayOfMonth": 19,
"dayOfWeek": "WEDNESDAY",
"dayOfYear": 353,
"hour": 11,
"minute": 22,
"month": "DECEMBER",
"monthValue": 12,
"nano": 884499000,
"second": 17,
"year": 2018
},
"id": 7,
"user": {
"id": 5,
"name": "admin",
"password": "123"
}
}
]
BookRentals:
package bookrental.model.book;
import bookrental.model.account.User;
import lombok.*;
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
@Getter
@Setter
@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor
public class BookRentals {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@OneToOne
private Book book;
@OneToOne
private User user;
private LocalDateTime dateOfRental;
public BookRentals(Book book, User user) {
this.book = book;
this.user = user;
}
}
//EDIT2
Hey. Accidently I found the cause of problem. I've got class that is responsible for finding exact rantals for exact user. When I go to /books/rentals/{userID}
Im getting properly foramtted date. As you can see method return List<BookRentals>
. In BookRentalsService
I return ResponseEntity and I think because of that it looks like this. Do you know how to resolve it?
package bookrental.service.account;
import bookrental.model.book.BookRentals;
import bookrental.repository.book.BookRentalsRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserRentalsService {
private final BookRentalsRepository bookRentalsRepository;
@Autowired
public UserRentalsService(BookRentalsRepository bookRentalsRepository) {
this.bookRentalsRepository = bookRentalsRepository;
}
public List<BookRentals> findUserRentalsByGivenID(int userID) {
return bookRentalsRepository.getUserRentalsByGivenID(userID);
}
}
package bookrental.controller.account;
import bookrental.model.book.BookRentals;
import bookrental.service.account.UserRentalsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class UserRentalsController {
private final UserRentalsService userRentalsService;
@Autowired
public UserRentalsController(UserRentalsService userRentalsService) {
this.userRentalsService = userRentalsService;
}
@GetMapping("books/rentals/{userID}")
public List<BookRentals> findUserRentalsByGivenID(@PathVariable int userID) {
return userRentalsService.findUserRentalsByGivenID(userID);
}
}
BookRentalsService
package bookrental.service.book.rentals;
import bookrental.model.account.User;
import bookrental.model.book.Book;
import bookrental.model.book.BookRentals;
import bookrental.repository.account.UserRepository;
import bookrental.repository.book.BookRepository;
import bookrental.repository.book.BookRentalsRepository;
import flexjson.JSONSerializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Service
public class BookRentalService {
private final UserRepository userRepository;
private final BookRepository bookRepository;
private final BookRentalsRepository bookRentalsRepository;
@Autowired
public BookRentalService(BookRepository bookRepository, BookRentalsRepository bookRentalsRepository, UserRepository userRepository) {
this.bookRepository = bookRepository;
this.bookRentalsRepository = bookRentalsRepository;
this.userRepository = userRepository;
}
....
public ResponseEntity<String> findAllRentals() {
List<BookRentals> rentedBooks = new ArrayList<>();
bookRentalsRepository.findAll().forEach(rentedBooks::add);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
return new ResponseEntity<>(new JSONSerializer().exclude("book.class")
.exclude("book.available")
.exclude("dateOfReturn")
.exclude("*.class")
.exclude("user.amountOfCashToPay")
.exclude("password")
.serialize(rentedBooks), headers, HttpStatus.OK);
}
}
Upvotes: 5
Views: 11829
Reputation: 51
Here is what did the trick for me, running Spring Boot 3.0.2:
I just added the annotation
@JsonFormat(shape = Shape.STRING)
to the regarding field inside my dto, resulting in
@JsonFormat(shape = Shape.STRING)
private LocalDateTime timestamp;
This way the result went from
"timestamp": [
2023,
2,
3,
12,
29,
20,
584451000
],
to the wanted ISO format
"timestamp": "2023-02-03T12:29:20.584451",
The reason this happens is because the default value for the json format is Shape.ANY
and the now isolated ObjectMapper
parses single integers to an array. The annotation forces the ObjectMapper
to actually parse the value as a String.
Upvotes: 2
Reputation: 7808
In your code remove the annotation @JsonSerialize(using = LocalDateTimeSerializer.class)
and modify your annotation @JsonFormat(pattern = ("yyyy/MM/dd HH:mm:ss"))
to this:
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy/MM/dd HH:mm:ss"))
See Spring Data JPA - ZonedDateTime format for json serialization for more details
Upvotes: 0
Reputation: 14677
This is an updated example using Spring 2.1.1:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
@SpringBootApplication
class PipilamApplication {
public static void main(String[] args) {
SpringApplication.run(PipilamApplication.class, args);
}
}
@RestController
class Controller {
@GetMapping("/demo")
public Demo demo() {
return new Demo("pipilam",LocalDateTime.now());
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Demo {
String name;
LocalDateTime dateTime;
}
Connecting to http://localhost:8080/demo gives the following output:
{"name":"pipilam","dateTime":"2018-12-19T20:16:12.780268"}
No configuration nor annotations needed. Consider my previous answer deprecated. This is the pom.xml I used:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.stackoverflow</groupId>
<artifactId>pipilam</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>pipilam</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
You can find the project in Github here: https://github.com/bodiam/spring-boot-java8-json-time
Upvotes: 1
Reputation: 1637
Do you even need the @JsonSerialize(using = LocalDateTimeSerializer.class)
and @JsonDeserialize(using = LocalDateTimeDeserializer.class)
?
I had the exact same problem, also using the jackson-datatype-jsr310
dependency. Switching to spring-boot-starter-json solved the issue for me:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
Upvotes: 0