Spring Data JPA - Zoneddatetime Format for JSON Serialization

Spring Data JPA - ZonedDateTime format for json serialization

I guess that you are using Jackson for json serialization, Jackson now has a module for Java 8 new date time API, https://github.com/FasterXML/jackson-datatype-jsr310.

Add this dependency into your pom.xml

<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.6.0</version>
</dependency>

And this is its usage:

 public static void main(String[] args) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
System.out.println(objectMapper.writeValueAsString(new Entity()));
}

static class Entity {
ZonedDateTime time = ZonedDateTime.now();

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
public ZonedDateTime getTime() {
return time;
}
}

The output is:

{"time":"2015-07-25T23:09:01.795+0700"}

Note : If your Jackson version is 2.4.x use

objectMapper.registerModule(new JSR310Module());

Hope this helps!

How to serialize an Instant without nanoseconds using Spring Boot with Jackson?

For that you could use @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS]")

Full example:

    import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;

public class Message {

@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS]")
private final LocalDateTime dateTime;

@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS]")
private final ZonedDateTime zonedDateTime;

public Message(ZonedDateTime zonedDateTime) {
this(zonedDateTime.toLocalDateTime(), zonedDateTime);
}

public Message(LocalDateTime dateTime, ZonedDateTime zonedDateTime) {
this.dateTime = dateTime;
this.zonedDateTime = zonedDateTime;
}

public LocalDateTime getDateTime() {
return dateTime;
}

public ZonedDateTime getZonedDateTime() {
return zonedDateTime;
}
}

Test:

    import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.json.JsonTest;
import java.time.*;
import java.time.temporal.ChronoUnit;
import static org.junit.jupiter.api.Assertions.*;

@JsonTest
class MessageTest {

@Autowired
ObjectMapper mapper;

@Test
public void serializationTest() throws JsonProcessingException {
final LocalDate date = LocalDate.of(2000, Month.JANUARY, 1);
final LocalTime time = LocalTime.of(12, 20, 10).plus(123, ChronoUnit.MILLIS);
final Message message = new Message(ZonedDateTime.of(date, time, ZoneId.systemDefault()));

final String res = mapper.writeValueAsString(message);

assertEquals("{\"dateTime\":\"2000-01-01T12:20:10.123\",\"zonedDateTime\":\"2000-01-01T12:20:10.123\"}", res);
}

}

Update:

If you want to configure it centrally you could:

  1. Try to set the date format to your ObjectMapper as described here
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"));

  1. Customize your mapper like described here
@SpringBootApplication
public class InstantSerializerApplication {

public static void main(String[] args) {
SpringApplication.run(InstantSerializerApplication.class, args);
}

@Bean
public Jackson2ObjectMapperBuilderCustomizer addCustomTimeSerialization() {
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.serializerByType(ZonedDateTime.class, new JsonSerializer<ZonedDateTime>() {
@Override
public void serialize(ZonedDateTime zonedDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
jsonGenerator.writeString(formatter.format(zonedDateTime));
}
});
}
}

Jackson serializes a ZonedDateTime wrongly in Spring Boot

There is a library jackson-datatype-jsr310. Try it.

This library covers new datetime API and includes serializers for ZonedDateTime too.

All you need is just to add JavaTimeModule:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());

UPDATE

To convert datetime to ISO-8601 string you should disable WRITE_DATES_AS_TIMESTAMPS feature. You can easily do by either overriding ObjectMapper bean or by using application properties:

spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS = false

Java Date format and JSON - Object in Debugger shows another format than toString()

First of all, Debugger displays date in whatever format its configured and has nothing to do with how you format your date. Date internally is stored as long value that holds the number of milliseconds since midnight of Jan 1, 1970 and and it doesn't hold any formatting info. If you format your date into a string and look at it in the debugger than you will see it exactly in the way you formatted your date. Now, for your issue, first of all please stop using class Date and even more so SimpleDateFormat they are definitely outdated (pun intended). Please look at java.time package and the classes that you should be using are DateTimeFormatter and TemporalAccessor interrface implementations such as ZonedDateTime, OffsetDateTime LocalDateTime or any other that might fit your needs. As for a date field in your DTO annotate it like this:

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
ZonedDateTime proposalDate;

For more details look at the great answer for this question: Spring Data JPA - ZonedDateTime format for json serialization

How can i convert time from milis to date with time?

Change your class as follows:

public class Test{
private String name;

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
private ZonedDateTime date1;

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
private ZonedDateTime date2;

This should resolve your problem.

Source: Spring Data JPA - ZonedDateTime format for json serialization

Deserialize JSON date format to ZonedDateTime using objectMapper

I have control only over the ObjectMapper. Is there any possible configuration that can make this work?

As long as you are happy with default values for the time and for the timezone, you could work around it with a custom deserializer:

public class ZonedDateTimeDeserializer extends JsonDeserializer<ZonedDateTime> {

@Override
public ZonedDateTime deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext)
throws IOException {

LocalDate localDate = LocalDate.parse(
jsonParser.getText(),
DateTimeFormatter.ISO_LOCAL_DATE);

return localDate.atStartOfDay(ZoneOffset.UTC);
}
}

Then add it to a module and register the module to your ObjectMapper instance:

SimpleModule module = new SimpleModule();
module.addDeserializer(ZonedDateTime.class, new ZonedDateTimeDeserializer());

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);

If adding the deserializer to a module doesn't suit you (in the sense this configuration will be applied to other ZonedDateTime instances), then you could rely on mix-ins to define which fields the deserializer will be applied to. First define a mix-in interface, as shown below:

public interface MarkdownMixIn {

@JsonDeserialize(using = ZonedDateTimeDeserializer.class)
ZonedDateTime getDate();
}

And then bind the mix-in interface to the desired class:

ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(Markdown.class, MarkdownMixIn.class);

How to deserialize date '2017-01-01T00:00:59.000UTC'

The date format that you are using is incorrect.

Instead of: yyyy-MM-dd'T'HH:mm:ss.SSS'UTC'

it should be: yyyy-MM-dd'T'HH:mm:ss.SSSz

Secondly, you need to use @JsonFormat to specify the date format.

@JsonFormat which is defined in jackson-databind package gives you more control on how to format Date and Calendar values according to SimpleDateFormat.

By using this, the POJO MyClass would look something like this:

@Data
public class MyClass {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSz", timezone = "UTC")
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime date;
}

Now, if you try to deserialize using:

ObjectMapper mapper = new ObjectMapper();
MyClass clazz = mapper.readValue(new File("MyFile.json"), MyClass.class);
System.out.println(myClass);

Then the process would go through, producing a result something like this:

MyClass{date=2017-01-01T00:00:59.000}

JSON Java 8 LocalDateTime format in Spring Boot

update: Spring Boot 2.x doesn't require this configuration anymore. I've written a more up to date answer here.


(This is the way of doing it before Spring Boot 2.x, it might be useful for people working on an older version of Spring Boot)

I finally found here how to do it. To fix it, I needed another dependency:

compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.4.0")

By including this dependency, Spring will automatically register a converter for it, as described here. After that, you need to add the following to application.properties:

spring.jackson.serialization.write_dates_as_timestamps=false

This will ensure that a correct converter is used, and dates will be printed in the format of 2016-03-16T13:56:39.492

Annotations are only needed in case you want to change the date format.



Related Topics



Leave a reply



Submit