Time format json java

Java 8 date time JSON formatting with Jackson

First of all we need to create a new Spring Boot 2.2.0 based project. The below gradle file will manage the dependencies for setting up Spring MVC.

plugins < id 'org.springframework.boot' version '2.2.0.RELEASE' id 'io.spring.dependency-management' version '1.0.8.RELEASE' id 'java' >group = 'com.shunya' version = '0.0.1-SNAPSHOT' sourceCompatibility = '1.8' repositories < mavenCentral() >dependencies

Creating a POJO

We will create a simple POJO that holds different types of types i.e. java.util.Date, LocalDate, LocalDateTime, Instant.

import com.fasterxml.jackson.annotation.JsonFormat; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.Date; public class SampleDto < @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "Asia/Kolkata") private Instant instant; @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ") private Date date; @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate localDate; @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") private LocalDateTime localDateTime; //Getters and Setter omitted for brevity >

We will use this POJO for Jackson based JSON serialization/deserialization.

It is important to note here that we need to specify the timezone while dealing with java.time.Instant otherwise we will encounter the below exception:

nested exception is com.fasterxml.jackson.databind.JsonMappingException: Unsupported field: YearOfEra

Controller Layer

We will create a controller that exposes two endpoints — one with HTTP POST for SampleDto another for HTTP GET for SampleDto.

@RestController public class DateController < @PostMapping("/date") public SampleDto create(@RequestBody SampleDto payload) < return payload; >@GetMapping("/date") public SampleDto get() < final SampleDto dto = new SampleDto(); final Instant time = Instant.ofEpochMilli(1571884105000L); dto.setInstant(time); dto.setDate(new Date(time.toEpochMilli())); dto.setLocalDate(time.atZone(ZoneId.of("UTC")).toLocalDate()); dto.setLocalDateTime(time.atZone(ZoneId.of("UTC")).toLocalDateTime()); return dto; >>

JUNIT 5 test at Controller layer for JSR-310 types

Spring Boot 2.2.0 supports JUNIT5 out of the box without any custom configuration. All you need to do is to include the below dependency in build.gradle

Here we will just test the controller layer using JUNIT 5 based tests in Spring Boot.

@ExtendWith(SpringExtension.class) @WebMvcTest(DateController.class) class DateControllerTest < @Autowired private MockMvc mockMvc; @Test void postDate() throws Exception < //language=JSON String jsonPayload = ""; this.mockMvc.perform(MockMvcRequestBuilders .post("/date") .content(jsonPayload) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andDo(print()).andExpect(status().isOk()) .andExpect(content().string(CoreMatchers.notNullValue())); > >

WebMvcTest annotation just bootstraps the provided controller instead of loading the entire application context.

Spring DateTimeFormat vs Jackson JsonFormat

@JsonFormat is a Jackson annotation ( com.fasterxml.jackson.annotation ), while @DateTimeFormat is a Spring annotation.

Читайте также:  Что такое php openssl

@JsonFormat controls the formatting during JSON serialization/deserialization of java Date time classes (JSR-310 java.time types — LocalDate/LocalDateTime/Instant/Date, etc)

@DateTimeFormat on the other hand controls formatting of a bean in Spring when it is rendered ina view.

Github Repository

You can grab the github repository for this project from this link: https://github.com/cancerian0684/tutorial-jsonformat-spring-boot

Top articles in this category:

Источник

Formatting json Date/LocalDateTime/LocalDate in Spring Boot

Spring Boot uses jackson by default to serialize, deserialize json data.

By default, Jackson serializes Date objects as timestamps. For LocalDateTime , LocalDate objects, jackson doesn’t do anything special, it just treats them as basic Java objects.

 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 
import java.time.LocalDate; import java.time.LocalDateTime; import java.util.Date; import java.util.HashMap; import java.util.Map;  import com.fasterxml.jackson.databind.ObjectMapper;  public class MainTest    public static void main(String. args) throws Exception   ObjectMapper objectMapper = new ObjectMapper();   MapString, Object> map = new HashMap<>();  map.put("date", new Date());  map.put("localDateTime", LocalDateTime.now());  map.put("localDate", LocalDate.now());   String json = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(map);   System.out.println(json);  > > 
 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 
  "date" : 1663680273923,  "localDateTime" :   "dayOfMonth" : 20,  "dayOfWeek" : "TUESDAY",  "dayOfYear" : 263,  "month" : "SEPTEMBER",  "monthValue" : 9,  "year" : 2022,  "hour" : 21,  "minute" : 24,  "nano" : 992000000,  "second" : 33,  "chronology" :   "id" : "ISO",  "calendarType" : "iso8601"  >  >,  "localDate" :   "year" : 2022,  "month" : "SEPTEMBER",  "era" : "CE",  "dayOfMonth" : 20,  "dayOfWeek" : "TUESDAY",  "dayOfYear" : 263,  "leapYear" : false,  "monthValue" : 9,  "chronology" :   "id" : "ISO",  "calendarType" : "iso8601"  >  > > 

The above code runs normally in Java8. If you are in a higher version of java, such as java17, running the above code may throw an exception.

 1  2  3  4  5  6  7  8  9 10 11 12 13 14 
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.>LocalDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through >reference chain: java.util.HashMap["localDateTime"])  at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)  at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1300)  at com.fasterxml.jackson.databind.ser.impl.UnsupportedTypeSerializer.serialize(UnsupportedTypeSerializer.java:35)  at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFields(MapSerializer.java:808)  at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeWithoutTypeInfo(MapSerializer.java:764)  at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:720)  at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:35)  at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)  at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)  at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1518)  at com.fasterxml.jackson.databind.ObjectWriter._writeValueAndClose(ObjectWriter.java:1219)  at com.fasterxml.jackson.databind.ObjectWriter.writeValueAsString(ObjectWriter.java:1086)  at io.springboot.test.MainTest.main(MainTest.java:22) 

Date

The formatting of the Date object can be easily customized through the configuration properties provided by spring boot.

spring:  jackson:  # Date format string or a fully-qualified date format class name. For instance, 'yyyy-MM-dd HH:mm:ss'  date-format: "yyyy-MM-dd HH:mm:ss.SSS"  # Locale used for formatting  time-zone: "GMT+8" 

LocalDateTime & LocalDate

Spring Boot does not provide configuration properties for formatting LocalDateTime and LocalDate , but it does provide a Jackson2ObjectMapperBuilderCustomizer interface to easily customize the formatting of LocalDateTime and LocalDate .

 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 
import java.time.format.DateTimeFormatter;  import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;  import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;  @Configuration public class JacksonConfiguration    @Bean  public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer()    return builder ->    // formatter  DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");  DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");   // deserializers  builder.deserializers(new LocalDateDeserializer(dateFormatter));  builder.deserializers(new LocalDateTimeDeserializer(dateTimeFormatter));   // serializers  builder.serializers(new LocalDateSerializer(dateFormatter));  builder.serializers(new LocalDateTimeSerializer(dateTimeFormatter));  >;  > > 

Testing

A simple test to verify that the above code and configuration takes effect.

Controller

A simple Controller that reads and parses the client’s request body into a payload object, which defines the LocalDate , LocalDateTime fields. And it responds to the client with the payload object to verify that the custom formatting is working.

 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 
import java.time.LocalDate; import java.time.LocalDateTime; import java.util.Date; import java.util.HashMap; import java.util.Map;  import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;  import lombok.Data;  @Data class Payload   private LocalDate date;  private LocalDateTime dateTime; >  @RestController @RequestMapping("/test") public class TestController    @PostMapping  public Object test (@RequestBody Payload payload)   MapString, Object> ret = new HashMap<>();  ret.put("payload", payload); // request body  ret.put("now", new Date());  return ret;  > > 

Client

Use Postman to launch http requests.

 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 
POST /test HTTP/1.1 Content-Type: application/json User-Agent: PostmanRuntime/7.29.2 Accept: */* Postman-Token: 1b1cbcad-475e-49a9-ad5d-5a8163bd7b05 Host: localhost Accept-Encoding: gzip, deflate, br Connection: keep-alive Content-Length: 70   "date": "2022-09-20", "dateTime": "2022-09-20 21:02:00" >  HTTP/1.1 200 OK Content-Encoding: gzip Connection: keep-alive Server: PHP/7.3.1 X-Request-Id: 6038513c-fa65-49bf-8e6c-44f5db749832 Transfer-Encoding: chunked Content-Type: application/json Date: Tue, 20 Sep 2022 14:18:09 GMT  ,"now":"2022-09-20 22:18:09.318"> 

With the request and response logs, you can see that everything is OK.

For more information about the available configurations of jackson in spring boot, you can refer to the official documentation。

Источник

Jackson JSON — Using @JsonFormat to format Date and Enum

@JsonFormat is a general purpose annotation which can be used to serialize a particular type into a specific format.

package com.fasterxml.jackson.annotation; . public @interface JsonFormat< . // Datatype-specific configuration to further define formatting aspects. public String pattern() default ""; //Structure to use for serialization public Shape shape() default Shape.ANY; //java.util.Locale to use for serialization (if needed) public String locale() default DEFAULT_LOCALE; //java.util.TimeZone to use for serialization (if needed) public String timezone() default DEFAULT_TIMEZONE; //whether "lenient" handling should be enabled. //This is relevant mostly for deserialization of some textual // datatypes, especially date/time types public OptBoolean lenient() default OptBoolean.DEFAULT; //JsonFormat.Feature to explicitly enable for the annotated property public JsonFormat.Feature[] with() default < >; //JsonFormat.Feature to explicitly disable for the annotated property public JsonFormat.Feature[] without() default < >; . >

This tutorial will show how to serialize Date/Calendar and Java Enum in a desired format.

Formatting Date

By default Date/Calendar are serialized as number (i.e. milliseconds since epoch). To serialize them as string, the attribute @JsonFormat#shape should be assigned to JsonFormat.Shape.STRING along with the attribute @JsonFormat#pattern assigned to a desired SimpleDateFormat-compatible pattern. We can also optionally specify @JsonFormat#timezone or @JsonFormat#locale values. For example

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss Z", timezone="America/New_York") private Date startDate;

Formatting enum

By default enums are serialized by their names. To serialize them by ordinals, we can assign the shape as JsonFormat.Shape.NUMBER . For example:

@JsonFormat(shape = JsonFormat.Shape.NUMBER) private Dept dept;

Example

Java Object

With ‘dateOfBirth’ we just specify the string shape without any pattern; In that case a default String format will be serialized.

Serializing to JSON

-- before serialization --
Employee
-- after serialization --

-- after deserialization --
Employee

Without @JsonFormat

If we remove all @JsonFormat:

Employee — after serialization — — after deserialization — Employee

Example Project

Dependencies and Technologies Used:

  • jackson-databind 2.9.6: General data-binding functionality for Jackson: works on core streaming API.
  • JDK 10
  • Maven 3.5.4

Источник

Оцените статью