2. Serialize Date with Jackson
First – let’s see how to serialize a simple java.util.Date with Jackson.
In the following example – we will serialize an instance of “Event” which has a Date field “eventDate“:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@Test
public
void
whenSerializingDateWithJackson_thenSerializedToTimestamp()
throws
JsonProcessingException, ParseException {
SimpleDateFormat df =
new
SimpleDateFormat(
"dd-MM-yyyy hh:mm"
);
df.setTimeZone(TimeZone.getTimeZone(
"UTC"
));
Date date = df.parse(
"01-01-1970 01:00"
);
Event event =
new
Event(
"party"
, date);
ObjectMapper mapper =
new
ObjectMapper();
mapper.writeValueAsString(event);
}
|
What’s important here is that Jackson will serialize the Date to a timestamp format by default (number of milliseconds since January 1st, 1970, UTC).
The actual output of the “event” serialization is:
1
2
3
4
|
{
"name"
:
"party"
,
"eventDate"
:3600000
}
|
3. Serialize Date to ISO-8601
Clearly serializing to this terse timestamp format is not optimal. Let’s now serialize the Date to the ISO-8601format:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@Test
public
void
whenSerializingDateToISO8601_thenSerializedToText()
throws
JsonProcessingException, ParseException {
SimpleDateFormat df =
new
SimpleDateFormat(
"dd-MM-yyyy hh:mm"
);
df.setTimeZone(TimeZone.getTimeZone(
"UTC"
));
String toParse =
"01-01-1970 02:30"
;
Date date = df.parse(toParse);
Event event =
new
Event(
"party"
, date);
ObjectMapper mapper =
new
ObjectMapper();
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.setDateFormat(
new
ISO8601DateFormat());
String result = mapper.writeValueAsString(event);
assertThat(result, containsString(
"1970-01-01T02:30:00Z"
));
}
|
Note how the representation of the date is now much more readable.
4. Configure ObjectMapper DateFormat
The previous solutions still lack the full flexibility of choosing the exact format to represent the java.util.Dateinstances.
Let’s now take a look at a configuration that will allow us to set our own formats for representing dates:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@Test
public
void
whenSettingObjectMapperDateFormat_thenCorrect()
throws
JsonProcessingException, ParseException {
SimpleDateFormat df =
new
SimpleDateFormat(
"dd-MM-yyyy hh:mm"
);
String toParse =
"20-12-2014 02:30"
;
Date date = df.parse(toParse);
Event event =
new
Event(
"party"
, date);
ObjectMapper mapper =
new
ObjectMapper();
mapper.setDateFormat(df);
String result = mapper.writeValueAsString(event);
assertThat(result, containsString(toParse));
}
|
Note that, even though we’re now more flexible in terms of the date format – we’re still using a global configuration at the level of the entire ObjectMapper.
5. Use @JsonFormat to format Date
Next, let’s take a look at the @JsonFormat annotation to control the date format on individual classesinstead of globally, for the entire application:
1
2
3
4
5
6
7
|
public
class
Event {
public
String name;
@JsonFormat
(shape = JsonFormat.Shape.STRING, pattern =
"dd-MM-yyyy hh:mm:ss"
)
public
Date eventDate;
}
|
Now – let’s test it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@Test
public
void
whenUsingJsonFormatAnnotationToFormatDate_thenCorrect()
throws
JsonProcessingException, ParseException {
SimpleDateFormat df =
new
SimpleDateFormat(
"dd-MM-yyyy hh:mm:ss"
);
df.setTimeZone(TimeZone.getTimeZone(
"UTC"
));
String toParse =
"20-12-2014 02:30:00"
;
Date date = df.parse(toParse);
Event event =
new
Event(
"party"
, date);
ObjectMapper mapper =
new
ObjectMapper();
String result = mapper.writeValueAsString(event);
assertThat(result, containsString(toParse));
}
|
6. Custom Date Serializer
Next – to get full control over the output, we’ll leverage a custom serializer for Dates:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public
class
CustomDateSerializer
extends
StdSerializer<Date> {
private
SimpleDateFormat formatter
=
new
SimpleDateFormat(
"dd-MM-yyyy hh:mm:ss"
);
public
CustomDateSerializer() {
this
(
null
);
}
public
CustomDateSerializer(Class t) {
super
(t);
}
@Override
public
void
serialize (Date value, JsonGenerator gen, SerializerProvider arg2)
throws
IOException, JsonProcessingException {
gen.writeString(formatter.format(value));
}
}
|
Next – let’s use it as the serializer of our “eventDate” field:
1
2
3
4
5
6
|
public
class
Event {
public
String name;
@JsonSerialize
(using = CustomDateSerializer.
class
)
public
Date eventDate;
}
|
Finally – let’s test it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@Test
public
void
whenUsingCustomDateSerializer_thenCorrect()
throws
JsonProcessingException, ParseException {
SimpleDateFormat df =
new
SimpleDateFormat(
"dd-MM-yyyy hh:mm:ss"
);
String toParse =
"20-12-2014 02:30:00"
;
Date date = df.parse(toParse);
Event event =
new
Event(
"party"
, date);
ObjectMapper mapper =
new
ObjectMapper();
String result = mapper.writeValueAsString(event);
assertThat(result, containsString(toParse));
}
|
7. Serialize Joda-Time with Jackson
Dates aren’t always an instance of java.util.Date; actually – they’re more and more represented by some other class – and a common one is, of course, the DateTime implementation from the Joda-Time library.
Let’s see how we can serialize DateTime with Jackson.
We’ll make use of the jackson-datatype-joda module for out of the box Joda-Time support:
1
2
3
4
5
|
<
dependency
>
<
groupId
>com.fasterxml.jackson.datatype</
groupId
>
<
artifactId
>jackson-datatype-joda</
artifactId
>
<
version
>2.4.0</
version
>
</
dependency
>
|
And now we can simply register the JodaModule and be done:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@Test
public
void
whenSerializingJodaTime_thenCorrect()
throws
JsonProcessingException {
DateTime date =
new
DateTime(
2014
,
12
,
20
,
2
,
30
,
DateTimeZone.forID(
"Europe/London"
));
ObjectMapper mapper =
new
ObjectMapper();
mapper.registerModule(
new
JodaModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
String result = mapper.writeValueAsString(date);
assertThat(result, containsString(
"2014-12-20T02:30:00.000Z"
));
}
|
8. Serialize Joda DateTime with Custom Serializer
If we don’t want the extra Joda-Time Jackson dependency – we can also make use of a custom serializer(similar to the earlier examples) to get DateTime instances serialized cleanly:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public
class
CustomDateTimeSerializer
extends
StdSerializer<DateTime> {
private
static
DateTimeFormatter formatter =
DateTimeFormat.forPattern(
"yyyy-MM-dd HH:mm"
);
public
CustomDateTimeSerializer() {
this
(
null
);
}
public
CustomDateTimeSerializer(Class<DateTime> t) {
super
(t);
}
@Override
public
void
serialize
(DateTime value, JsonGenerator gen, SerializerProvider arg2)
throws
IOException, JsonProcessingException {
gen.writeString(formatter.print(value));
}
}
|
Next – let’s use it as our property “eventDate” serializer:
1
2
3
4
5
6
|
public
class
Event {
public
String name;
@JsonSerialize
(using = CustomDateTimeSerializer.
class
)
public
DateTime eventDate;
}
|
Finally – let’s put everything together and test it:
1
2
3
4
5
6
7
8
9
10
11
|
@Test
public
void
whenSerializingJodaTimeWithJackson_thenCorrect()
throws
JsonProcessingException {
DateTime date =
new
DateTime(
2014
,
12
,
20
,
2
,
30
);
Event event =
new
Event(
"party"
, date);
ObjectMapper mapper =
new
ObjectMapper();
String result = mapper.writeValueAsString(event);
assertThat(result, containsString(
"2014-12-20 02:30"
));
}
|
9. Serialize Java 8 Date with Jackson
Next – let’s see how to serialize Java 8 DateTime – in this example, LocalDateTime – using Jackson. We can make use of the jackson-datatype-jsr310 module:
1
2
3
4
5
|
<
dependency
>
<
groupId
>com.fasterxml.jackson.datatype</
groupId
>
<
artifactId
>jackson-datatype-jsr310</
artifactId
>
<
version
>2.4.0</
version
>
</
dependency
>
|
Now, all we need to do is register the JSR310Module and Jackson will take care of the rest:
1
2
3
4
5
6
7
8
9
10
11
12
|
@Test
public
void
whenSerializingJava8Date_thenCorrect()
throws
JsonProcessingException {
LocalDateTime date = LocalDateTime.of(
2014
,
12
,
20
,
2
,
30
);
ObjectMapper mapper =
new
ObjectMapper();
mapper.registerModule(
new
JSR310Module());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
String result = mapper.writeValueAsString(date);
assertThat(result, containsString(
"2014-12-20T02:30"
));
}
|
10. Serialize Java 8 Date Without any Extra Dependency
If you don’t want the extra dependency, you can always use a custom serializer to write out the Java 8DateTime to 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
|
public
class
CustomLocalDateTimeSerializer
extends
StdSerializer<LocalDateTime> {
private
static
DateTimeFormatter formatter =
DateTimeFormatter.ofPattern(
"yyyy-MM-dd HH:mm"
);
public
CustomLocalDateTimeSerializer() {
this
(
null
);
}
public
CustomLocalDateTimeSerializer(Class<LocalDateTime> t) {
super
(t);
}
@Override
public
void
serialize(
LocalDateTime value,
JsonGenerator gen,
SerializerProvider arg2)
throws
IOException, JsonProcessingException {
gen.writeString(formatter.format(value));
}
}
|
Next – let’s use the serializer for our “eventDate” field:
1
2
3
4
5
6
|
public
class
Event {
public
String name;
@JsonSerialize
(using = CustomLocalDateTimeSerializer.
class
)
public
LocalDateTime eventDate;
}
|
Now – let’s test it:
1
2
3
4
5
6
7
8
9
10
11
|
@Test
public
void
whenSerializingJava8DateWithCustomSerializer_thenCorrect()
throws
JsonProcessingException {
LocalDateTime date = LocalDateTime.of(
2014
,
12
,
20
,
2
,
30
);
Event event =
new
Event(
"party"
, date);
ObjectMapper mapper =
new
ObjectMapper();
String result = mapper.writeValueAsString(event);
assertThat(result, containsString(
"2014-12-20 02:30"
));
}
|
11. Deserialize Date
Next – let’s see how to deserialize a Date with Jackson. In the following example – we deserialize an “Event” instance containing a date:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@Test
public
void
whenDeserializingDateWithJackson_thenCorrect()
throws
JsonProcessingException, IOException {
String json =
"{"
name
":"
party
","
eventDate
":"
20
-
12
-
2014
02
:
30
:
00
"}"
;
SimpleDateFormat df =
new
SimpleDateFormat(
"dd-MM-yyyy hh:mm:ss"
);
ObjectMapper mapper =
new
ObjectMapper();
mapper.setDateFormat(df);
Event event = mapper.readerFor(Event.
class
).readValue(json);
assertEquals(
"20-12-2014 02:30:00"
, df.format(event.eventDate));
}
|
12. Custom Date Deserializer
Let’s also see how to use a custom Date deserializer; we’ll write a custom deserializer for the property “eventDate“:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public
class
CustomDateDeserializer
extends
StdDeserializer<Date> {
private
SimpleDateFormat formatter =
new
SimpleDateFormat(
"dd-MM-yyyy hh:mm:ss"
);
public
CustomDateDeserializer() {
this
(
null
);
}
public
CustomDateDeserializer(Class<?> vc) {
super
(vc);
}
@Override
public
Date deserialize(JsonParser jsonparser, DeserializationContext context)
throws
IOException, JsonProcessingException {
String date = jsonparser.getText();
try
{
return
formatter.parse(date);
}
catch
(ParseException e) {
throw
new
RuntimeException(e);
}
}
}
|
Next – let’s use it as the “eventDate” deserializer:
1
2
3
4
5
6
|
public
class
Event {
public
String name;
@JsonDeserialize
(using = CustomDateDeserializer.
class
)
public
Date eventDate;
}
|
And finally – let’s test it:
1
2
3
4
5
6
7
8
9
10
11
12
|
@Test
public
void
whenDeserializingDateUsingCustomDeserializer_thenCorrect()
throws
JsonProcessingException, IOException {
String json =
"{"
name
":"
party
","
eventDate
":"
20
-
12
-
2014
02
:
30
:
00
"}"
;
SimpleDateFormat df =
new
SimpleDateFormat(
"dd-MM-yyyy hh:mm:ss"
);
ObjectMapper mapper =
new
ObjectMapper();
Event event = mapper.readerFor(Event.
class
).readValue(json);
assertEquals(
"20-12-2014 02:30:00"
, df.format(event.eventDate));
}
|