Deserialize Java 8 LocalDateTime with JacksonMapper
The date time you're passing is not an ISO local date time format.
Change to
@Column(name = "start_date")
@DateTimeFormat(iso = DateTimeFormatter.ISO_LOCAL_DATE_TIME)
@JsonFormat(pattern = "YYYY-MM-dd HH:mm")
private LocalDateTime startDate;
and pass the date string in the format '2011-12-03T10:15:30'.
But if you still want to pass your custom format, you just have to specify the right formatter.
Change to
@Column(name = "start_date")
@DateTimeFormat(iso = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
@JsonFormat(pattern = "YYYY-MM-dd HH:mm")
private LocalDateTime startDate;
I think your problem is the @DateTimeFormat has no effect at all. As the Jackson is doing the deserialization and it doesn't know anything about spring annotation, and I don't see spring scanning this annotation in the deserialization context.
Alternatively, you can try setting the formatter while registering the Java time module.
LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);
Here is the test case with the deseralizer which works fine. Maybe try to get rid of that DateTimeFormat annotation altogether.
@RunWith(JUnit4.class)
public class JacksonLocalDateTimeTest {
private ObjectMapper objectMapper;
@Before
public void init() {
JavaTimeModule module = new JavaTimeModule();
LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);
objectMapper = Jackson2ObjectMapperBuilder.json()
.modules(module)
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.build();
}
@Test
public void test() throws IOException {
final String json = "{ \"date\": \"2016-11-08 12:00\" }";
final JsonType instance = objectMapper.readValue(json, JsonType.class);
assertEquals(LocalDateTime.parse("2016-11-08 12:00",DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm") ), instance.getDate());
}
}
class JsonType {
private LocalDateTime date;
public LocalDateTime getDate() {
return date;
}
public void setDate(LocalDateTime date) {
this.date = date;
}
}
serialize/deserialize java 8 java.time with Jackson JSON mapper
There's no need to use custom serializers/deserializers here. Use jackson-modules-java8's datetime module:
Datatype module to make Jackson recognize Java 8 Date & Time API data types (JSR-310).
This module adds support for quite a few classes:
- Duration
- Instant
- LocalDateTime
- LocalDate
- LocalTime
- MonthDay
- OffsetDateTime
- OffsetTime
- Period
- Year
- YearMonth
- ZonedDateTime
- ZoneId
- ZoneOffset
Deserialize LocalDateTime from String with Jackson
The problem is not related with JSON deserialization, but rather with the time format string:
pattern = "yyyy-MM-dd hh:mm:ss"
Please notice that the hours are set as hh
: this is a 12-hour formatter, which requires "AM" or "PM" values.
If the pattern is changed to
pattern = "yyyy-MM-dd HH:mm:ss"
the problem should be solved.
Jackson deserialize LocalDateTime
Replace the pattern as pattern = DateTimeFormatter.ISO_OFFSET_DATE_TIME
Your date-time string is already in the format specified by DateTimeFormatter.ISO_OFFSET_DATE_TIME
which is the default format used by OffsetDateTime#parse
.
Demo:
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
public class Main {
public static void main(String[] args) {
String dateTimeStr = "2020-10-01T15:30:27.4394205+03:00";
// Parse the date-time string into OffsetDateTime
OffsetDateTime odt = OffsetDateTime.parse(dateTimeStr);
System.out.println(odt);
// LocalDateTime from OffsetDateTime
LocalDateTime ldt = odt.toLocalDateTime();
System.out.println(ldt);
}
}
Output:
2020-10-01T15:30:27.439420500+03:00
2020-10-01T15:30:27.439420500
Spring boot: JSON deserialize date and time with time zone to LocalDateTime
There are two problems with your code:
1. Use of wrong type
Cannot deserialize value of type
java.time.LocalDateTime
from String
"2019-10-21T13:00:00+02:00": Failed to deserialize
java.time.LocalDateTime: (java.time.format.DateTimeParseException)
Text '2019-10-21T13:00:00+02:00' could not be parsed, unparsed text
found at index 19
If you analyze the error message, you will find that it is clearly telling you that there is some problem at index 19.
2019-10-21T13:00:00+02:00
// index 19 ----> ^
And, the problem is that LocalDateTime
does not support timezone. Given below is an overview of java.time types and you can see that the type which matches with your date-time string is OffsetDateTime
because it has a zone offset of +02:00
hours.
Change your declaration as follows:
private OffsetDateTime startTime;
2. Use of wrong format
You need to use XXX
for the offset part i.e. your format should be uuuu-MM-dd'T'HH:m:ssXXX
. If you want to stick to Z
, you need to use ZZZZZ
. Check the documentation page of DateTimeFormatter
for more details.
Demo:
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
String strDateTime = "2019-10-21T13:00:00+02:00";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:m:ssXXX");
OffsetDateTime odt = OffsetDateTime.parse(strDateTime, dtf);
System.out.println(odt);
}
}
Output:
2019-10-21T13:00+02:00
Learn more about the modern date-time API from Trail: Date Time.
Also related, RFC3339 - Date and Time on the Internet: Timestamps
This document defines a date and time format for use in Internet
protocols that is a profile of the ISO 8601 standard for
representation of dates and times using the Gregorian calendar.
LocalDateTime - deserialization with LocalDateTime.parse
Vanilla Jackson doesn't have a way to deserialize a LocalDateTime
object from any JSON string value.
You have a few options. You can create and register your own JsonDeserializer
which will use LocalDateTime#parse
.
class ParseDeserializer extends StdDeserializer<LocalDateTime> {
public ParseDeserializer() {
super(LocalDateTime.class);
}
@Override
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
return LocalDateTime.parse(p.getValueAsString()); // or overloaded with an appropriate format
}
}
...
@JsonSerialize(using = ToStringSerializer.class)
@JsonDeserialize(using = ParseDeserializer.class)
private LocalDateTime initiationDate;
Or you can add Jackson's java.time
extension to your classpath and register the appropriate Module
with your ObjectMapper
.
objectMapper.registerModule(new JavaTimeModule());
and let Jackson do the conversion for you. Internally, this uses LocalDateTime#parse
with one of the standard formats. Fortunately, it supports values like
2016-05-11T17:32:20.897
out of the box.
Java 8 LocalDate Jackson format
I was never able to get this to work simple using annotations. To get it to work, I created a ContextResolver
for ObjectMapper
, then I added the JSR310Module
(update: now it is JavaTimeModule
instead), along with one more caveat, which was the need to set write-date-as-timestamp to false. See more at the documentation for the JSR310 module. Here's an example of what I used.
Dependency
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.4.0</version>
</dependency>
Note: One problem I faced with this is that the jackson-annotation
version pulled in by another dependency, used version 2.3.2, which cancelled out the 2.4 required by the jsr310
. What happened was I got a NoClassDefFound for ObjectIdResolver
, which is a 2.4 class. So I just needed to line up the included dependency versions
ContextResolver
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JSR310Module;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
private final ObjectMapper MAPPER;
public ObjectMapperContextResolver() {
MAPPER = new ObjectMapper();
// Now you should use JavaTimeModule instead
MAPPER.registerModule(new JSR310Module());
MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
}
@Override
public ObjectMapper getContext(Class<?> type) {
return MAPPER;
}
}
Resource class
@Path("person")
public class LocalDateResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getPerson() {
Person person = new Person();
person.birthDate = LocalDate.now();
return Response.ok(person).build();
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response createPerson(Person person) {
return Response.ok(
DateTimeFormatter.ISO_DATE.format(person.birthDate)).build();
}
public static class Person {
public LocalDate birthDate;
}
}
Test
curl -v http://localhost:8080/api/person
Result:{"birthDate":"2015-03-01"}
curl -v -POST -H "Content-Type:application/json" -d "{\"birthDate\":\"2015-03-01\"}" http://localhost:8080/api/person
Result:2015-03-01
See also here for JAXB solution.
UPDATE
The JSR310Module
is deprecated as of version 2.7 of Jackson. Instead, you should register the module JavaTimeModule
. It is still the same dependency.
Deserialize '2021-09-24 00:00:00' date format via Jackson when using lombok @Builder
Gets fixed by:
@Getter
@Builder
@JsonDeserialize(builder = AdGroup.AdGroupBuilder.class)
public class AdGroup {
public static class AdGroupBuilder {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime uploadDate;
}
@JsonProperty("upload_date")
private LocalDateTime uploadDate;
}
Related Topics
Why Aren't Integers Cached in Java
How Does Bitshifting Work in Java
How Can "This" of the Outer Class Be Accessed from an Inner Class
Any Recommended Java Profiling Tutorial
Checked VS Unchecked Exceptions in Java
File Upload Using Selenium Webdriver and Java Robot Class
How to Implement Task Prioritization Using an Executorservice in Java 5
How to Specify the Jdk for a Glassfish Domain
Does Variable = Null Set It for Garbage Collection
What Are the Date Formats Available in Simpledateformat Class
How to Use Google's Gson API to Deserialize JSON Properly
How to Change the Name of a Java Application Process
Problems Resteasy 3.09 Corsfilter
How to Stop the Task Scheduled in Java.Util.Timer Class
Any Simple Way to Explain Why I Cannot Do List<Animal> Animals = New Arraylist<Dog>()