LATER EDIT 2019-05-31
If I write a sample main method which instantiates an Item and then call String s = new ObjectMapper().writeValueAsString(item);, then the custom serializer is called correctly and has effect.
The issue only appears when the whole app is deployed in an Apache TomEE server.
LATER EDIT: it's not an issue with placement of annotation (on field vs. on getter), I tried various combinations of this (annotation on getter, annotation on private field, annotation on public field, etc...)
The code:
import com.fasterxml.jackson....
// YES, all JSON-related stuff is from fasterxml
#JsonAutoDetect
public class Item {
private Date lastModified;
#JsonSerialize(using = CSer.class)
public Date getLastModified() {
return lastModified;
}
public class CSer extends JsonSerializer<Date> {
public SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
#Override
public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers)
throws IOException, JsonProcessingException {
gen.writeString(dateFormat.format(value));
}
}
}
// some place else, in a REST service class
...
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getItems(... {
...
return Response.ok(result.getData()).build();
// result.getData() is an ArrayList of "Item" objects.
}
The ISSUES:
from what I know, the default JSON output format of the date should be the timestamp. In my case, it's not, instead it's yyyyMMddHHmmssZ
the custom serializer has no effect, I cannot change the output format of the date, and the serialize method never gets called.
The jackson files in my lib folder: jackson-annotations-2.8.0.jar, jackson-core-2.8.8.jar, jackson-databind-2.8.8.1.jar.
What am I doing wrong ?
Thank you.
It might have something to do with your annotation being placed on the getter - you might move it to reflect something similar to
public class Item {
#JsonSerialize(using = CSer.class)
private Date lastModified;
// ...
}
or you have to configure Jackson to only use getters for serialization.
Related
I'm writing a application using Spring boot and jackson for JSON parsing. I need to handle another service which produces JSON like this:
{
"task-id": 5081,
"task-created-on": {
"java.util.Date": 1631022026000
}
}
Notably, certain fields like the date field here are serialized into a map with a single key-value pair, where the key is a java classname and the value is the actual value of the field.
I've been going through the jackson documentation and haven't found anything about this format. Is there a way to configure jackson to produce and parse fields in this format?
At a minimum, I need to handle dates formatted this way. But I believe the service also uses this format for other objects, where the map key will be the name of some arbitrary java class and the value will be a map of its own. So I'd be interested in a solution that handles more than just dates if possible.
It can be easily done with custom serializer in Jackson by following steps.
First, create objects for serialization as follows:
class MyDateObject {
private Date date;
//general getter/setter
}
class Task {
#JsonProperty("task-id")
private int taskId;
#JsonProperty("task-created-on")
private MyDateObject taskCreatedOn;
//general getters/setters
}
Second, define your custom serializer: (Please note that I used myDateObject.getDate().getClass().getName() to get the class name of date field.)
class DateSerializer extends StdSerializer<MyDateObject> {
public DateSerializer() {
this(null);
}
protected DateSerializer(Class<MyDateObject> t) {
super(t);
}
#Override
public void serialize(MyDateObject myDateObject, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeNumberField(myDateObject.getDate().getClass().getName(), myDateObject.getDate().getTime());
jsonGenerator.writeEndObject();
}
}
Finally, register the serializer with ObjectMapper for the MyDateObject class and perform the serialization:
MyDateObject myDateObject = new MyDateObject();
myDateObject.setDate(new Date());
Task task = new Task();
task.setTaskId(5081);
task.setTaskCreatedOn(myDateObject);
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(MyDateObject.class, new DateSerializer());
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(simpleModule);
System.out.println(objectMapper.writeValueAsString(task));
The expected output is:
{"task-id":5081,"task-created-on":{"java.util.Date":1633402076254}}
Please refer to Jackson – Custom Serializer for more information.
It is possible to solve the issue with the use of a custom JsonSerializer and applying the JsonSerialize over the fields in the pojo you are interested like below :
public class Task {
#JsonProperty("task-id")
private int taskId;
#JsonProperty("task-created-on")
#JsonSerialize(using = ObjectSerializer.class)
Date taskCreatedOn;
}
The custom serializer will use the JsonGenerator.html#writeObjectField to serialize a generic object (Date or other java class) as propertyname : {"classname" : value} :
public class ObjectSerializer extends JsonSerializer<Object> {
#Override
public void serialize(Object t, JsonGenerator jg, SerializerProvider sp) throws IOException {
jg.writeStartObject();
jg.writeObjectField(t.getClass().getName(), t);
jg.writeEndObject();
}
}
I have the following code with Jackson:
public class Header implements Serializable {
#JsonProperty("numeroUnico")
private Integer numeroCliente;
#JsonProperty("oficina")
private Integer oficina;
#JsonProperty("fecha")
#JsonSerialize(using = CustomDateSerializer.class)
private Date fechaInscripcion;
}
this is my class "CustomDateSerializer.class"
public class CustomDateSerializer extends StdSerializer<Date> {
private SimpleDateFormat formatter
= new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
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));
}
}
They asked me to migrate all the implementations of Jackson to Gson.
Taking into account that the notation in Jackson #JsonProperty has an equivalence in Gson that is #SerializedName.
But for the notation in Jackson of:
#JsonSerialize (using = CustomDateSerializer.class)
What is its equivalent for Gson? if not, as it should be the implementation for attributes of type Date in my DTO.
I think the closest and probably the only match is #TypeAdapter. However you need to code either JsonSerializer<T> or TypeAdapter<T> to be used with that annotation.
For example how to make something like your CustomDateSerializer see accepted answer for this question.
Or maybe you can wrap your existing CustomDateSerializer with Gson TypeAdapter<Date> and use that in the annotation.
I have a Date format coming from API like this:
"start_time": "2015-10-1 3:00 PM GMT+1:00"
Which is YYYY-DD-MM HH:MM am/pm GMT timestamp.
I am mapping this value to a Date variable in POJO. Obviously, its showing conversion error.
I would like to know 2 things:
What is the formatting I need to use to carry out conversion with Jackson? Is Date a good field type for this?
In general, is there a way to process the variables before they get mapped to Object members by Jackson? Something like, changing the format, calculations, etc.
Since Jackson v2.0, you can use #JsonFormat annotation directly on Object members;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm a z")
private Date date;
What is the formatting I need to use to carry out conversion with Jackson? Is Date a good field type for this?
Date is a fine field type for this. You can make the JSON parse-able pretty easily by using ObjectMapper.setDateFormat:
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm a z");
myObjectMapper.setDateFormat(df);
In general, is there a way to process the variables before they get mapped to Object members by Jackson? Something like, changing the format, calculations, etc.
Yes. You have a few options, including implementing a custom JsonDeserializer, e.g. extending JsonDeserializer<Date>. This is a good start.
Of course there is an automated way called serialization and deserialization and you can define it with specific annotations (#JsonSerialize,#JsonDeserialize) as mentioned by pb2q as well.
You can use both java.util.Date and java.util.Calendar
... and probably JodaTime as well.
The #JsonFormat annotations not worked for me as I wanted (it has adjusted the timezone to different value) during deserialization (the serialization worked perfect):
#JsonFormat(locale = "hu", shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm", timezone = "CET")
#JsonFormat(locale = "hu", shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm", timezone = "Europe/Budapest")
You need to use custom serializer and custom deserializer instead of the #JsonFormat annotation if you want predicted result. I have found real good tutorial and solution here http://www.baeldung.com/jackson-serialize-dates
There are examples for Date fields but I needed for Calendar fields so here is my implementation:
The serializer class:
public class CustomCalendarSerializer extends JsonSerializer<Calendar> {
public static final SimpleDateFormat FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm");
public static final Locale LOCALE_HUNGARIAN = new Locale("hu", "HU");
public static final TimeZone LOCAL_TIME_ZONE = TimeZone.getTimeZone("Europe/Budapest");
#Override
public void serialize(Calendar value, JsonGenerator gen, SerializerProvider arg2)
throws IOException, JsonProcessingException {
if (value == null) {
gen.writeNull();
} else {
gen.writeString(FORMATTER.format(value.getTime()));
}
}
}
The deserializer class:
public class CustomCalendarDeserializer extends JsonDeserializer<Calendar> {
#Override
public Calendar deserialize(JsonParser jsonparser, DeserializationContext context)
throws IOException, JsonProcessingException {
String dateAsString = jsonparser.getText();
try {
Date date = CustomCalendarSerializer.FORMATTER.parse(dateAsString);
Calendar calendar = Calendar.getInstance(
CustomCalendarSerializer.LOCAL_TIME_ZONE,
CustomCalendarSerializer.LOCALE_HUNGARIAN
);
calendar.setTime(date);
return calendar;
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
and the usage of the above classes:
public class CalendarEntry {
#JsonSerialize(using = CustomCalendarSerializer.class)
#JsonDeserialize(using = CustomCalendarDeserializer.class)
private Calendar calendar;
// ... additional things ...
}
Using this implementation the execution of the serialization and deserialization process consecutively results the origin value.
Only using the #JsonFormat annotation the deserialization gives different result I think because of the library internal timezone default setup what you can not change with annotation parameters (that was my experience with Jackson library 2.5.3 and 2.6.3 version as well).
To add characters such as T and Z in your date
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'")
private Date currentTime;
output
{
"currentTime": "2019-12-11T11:40:49Z"
}
Just a complete example for spring boot application with RFC3339 datetime format
package bj.demo;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import java.text.SimpleDateFormat;
/**
* Created by BaiJiFeiLong#gmail.com at 2018/5/4 10:22
*/
#SpringBootApplication
public class BarApp implements ApplicationListener<ApplicationReadyEvent> {
public static void main(String[] args) {
SpringApplication.run(BarApp.class, args);
}
#Autowired
private ObjectMapper objectMapper;
#Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"));
}
}
Building on #miklov-kriven's very helpful answer, I hope these two additional points of consideration prove helpful to someone:
(1) I find it a nice idea to include serializer and de-serializer as static inner classes in the same class. NB, using ThreadLocal for thread safety of SimpleDateFormat.
public class DateConverter {
private static final ThreadLocal<SimpleDateFormat> sdf =
ThreadLocal.<SimpleDateFormat>withInitial(
() -> {return new SimpleDateFormat("yyyy-MM-dd HH:mm a z");});
public static class Serialize extends JsonSerializer<Date> {
#Override
public void serialize(Date value, JsonGenerator jgen SerializerProvider provider) throws Exception {
if (value == null) {
jgen.writeNull();
}
else {
jgen.writeString(sdf.get().format(value));
}
}
}
public static class Deserialize extends JsonDeserializer<Date> {
#Overrride
public Date deserialize(JsonParser jp, DeserializationContext ctxt) throws Exception {
String dateAsString = jp.getText();
try {
if (Strings.isNullOrEmpty(dateAsString)) {
return null;
}
else {
return new Date(sdf.get().parse(dateAsString).getTime());
}
}
catch (ParseException pe) {
throw new RuntimeException(pe);
}
}
}
}
(2) As an alternative to using #JsonSerialize and #JsonDeserialize annotations on each individual class member you could also consider overriding Jackson's default serialization by applying the custom serialization at an application level, that is all class members of type Date will be serialized by Jackson using this custom serialization without explicit annotation on each field. If you are using Spring Boot for example one way to do this would as follows:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public Module customModule() {
SimpleModule module = new SimpleModule();
module.addSerializer(Date.class, new DateConverter.Serialize());
module.addDeserializer(Date.class, new Dateconverter.Deserialize());
return module;
}
}
If anyone has problems with using a custom dateformat for java.sql.Date, this is the simplest solution:
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(java.sql.Date.class, new DateSerializer());
mapper.registerModule(module);
(This SO-answer saved me a lot of trouble: https://stackoverflow.com/a/35212795/3149048 )
Jackson uses the SqlDateSerializer by default for java.sql.Date, but currently, this serializer doesn't take the dateformat into account, see this issue: https://github.com/FasterXML/jackson-databind/issues/1407 .
The workaround is to register a different serializer for java.sql.Date as shown in the code example.
I want to point out that setting a SimpleDateFormat like described in the other answer only works for a java.util.Date which I assume is meant in the question.
But for java.sql.Date the formatter does not work.
In my case it was not very obvious why the formatter did not work because in the model which should be serialized the field was in fact a java.utl.Date but the actual object ended up beeing a java.sql.Date.
This is possible because
public class java.sql extends java.util.Date
So this is actually valid
java.util.Date date = new java.sql.Date(1542381115815L);
So if you are wondering why your Date field is not correctly formatted make sure that the object is really a java.util.Date.
Here is also mentioned why handling java.sql.Date will not be added.
This would then be breaking change, and I don't think that is warranted. If we were starting from scratch I would agree with the change, but as things are not so much.
Working for me. SpringBoot.
import com.alibaba.fastjson.annotation.JSONField;
#JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
output:
{
"createTime": "2019-06-14 13:07:21"
}
If we are having the spring boot application, then one more option thats simple to implement for app wide configuration is to use below in application properties file. You can customize the format as needed.
spring.jackson.date-format=yyyy-MM-dd'T'HH:mm:ss.SSS
NOTE: If using this solution use the Spring Dependency Injection to get the reference of the ObjectMapper class.
Cons of not using explicit format is sometimes while upgrading the libraries for jackson code breaks because of change in the format for some versions.
I have a simple Spring Boot Application having a simple MyDateTime model class only having a java.util.Date instance variable with private access, getters/setters and default constructor.
A controller just instantiates this object and returns back.
In the output, I see that default representation of Date object is done as an Integer (maybe millis from Epoch)
Is there any way I can change the default jsonification of Date Object into ISO-String or any other String?
EDIT:
Some Clarification:
I'm very new to Spring and Spring Boot. I'm using the template from a sample application on spring's website. JSONification is done through Jackson. Rest, I don't know much about Spring in general.
You can set the default format Jackson uses when serializing dates in your application.properties file:
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
http://docs.spring.io/spring-boot/docs/1.2.3.RELEASE/reference/htmlsingle/#common-application-properties
You can also specify a specific format to use for a specific date using the #JsonFormat annotation, example below:
Example POJO:
public class Demo {
private Date timestamp1;
private Date timestamp2;
public Date getTimestamp1() {
return timestamp1;
}
public void setTimestamp1(Date timestamp1) {
this.timestamp1 = timestamp1;
}
#JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd'T'HH:mm:ss.SSSZ")
public Date getTimestamp2() {
return timestamp2;
}
public void setTimestamp2(Date timestamp2) {
this.timestamp2 = timestamp2;
}
}
Example Controller:
#RestController
public class DemoController {
#RequestMapping(value="/demo", method = RequestMethod.GET)
Demo start() {
Demo demo = new Demo();
Date timestamp = new Date();
demo.setTimestamp1(timestamp);
demo.setTimestamp2(timestamp);
return demo;
}
}
https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations
Date.toString() method returns epoch timestamp by default. What you want to do is about Jackson internals. To accomplish that, change your MyDateTime class to something like this:
public class MyDateTime {
private final Date date;
public MyDateTime(Date date) {
this.date = date;
}
public Date date() { //this is not read by Jackson
return date;
}
public String getDate() { //this is read by Jackson
SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
return formatter.format(date);
}
}
When serializing, Jackson look for getter methods, the methods that start with get. If you don't want something to be serialized, remove get from the name. This is the simplest solution, you can check Jackson API for #JsonIgnore annotation for further solutions. If you want to see something other date in the field name in JSON string, look for #JsonProperty.
To print human readable date, you need SimpleDateFormat.
The examples works fine on my setup, I did not do anything further than returning custom class from HelloController.
I have a Date format coming from API like this:
"start_time": "2015-10-1 3:00 PM GMT+1:00"
Which is YYYY-DD-MM HH:MM am/pm GMT timestamp.
I am mapping this value to a Date variable in POJO. Obviously, its showing conversion error.
I would like to know 2 things:
What is the formatting I need to use to carry out conversion with Jackson? Is Date a good field type for this?
In general, is there a way to process the variables before they get mapped to Object members by Jackson? Something like, changing the format, calculations, etc.
Since Jackson v2.0, you can use #JsonFormat annotation directly on Object members;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm a z")
private Date date;
What is the formatting I need to use to carry out conversion with Jackson? Is Date a good field type for this?
Date is a fine field type for this. You can make the JSON parse-able pretty easily by using ObjectMapper.setDateFormat:
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm a z");
myObjectMapper.setDateFormat(df);
In general, is there a way to process the variables before they get mapped to Object members by Jackson? Something like, changing the format, calculations, etc.
Yes. You have a few options, including implementing a custom JsonDeserializer, e.g. extending JsonDeserializer<Date>. This is a good start.
Of course there is an automated way called serialization and deserialization and you can define it with specific annotations (#JsonSerialize,#JsonDeserialize) as mentioned by pb2q as well.
You can use both java.util.Date and java.util.Calendar
... and probably JodaTime as well.
The #JsonFormat annotations not worked for me as I wanted (it has adjusted the timezone to different value) during deserialization (the serialization worked perfect):
#JsonFormat(locale = "hu", shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm", timezone = "CET")
#JsonFormat(locale = "hu", shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm", timezone = "Europe/Budapest")
You need to use custom serializer and custom deserializer instead of the #JsonFormat annotation if you want predicted result. I have found real good tutorial and solution here http://www.baeldung.com/jackson-serialize-dates
There are examples for Date fields but I needed for Calendar fields so here is my implementation:
The serializer class:
public class CustomCalendarSerializer extends JsonSerializer<Calendar> {
public static final SimpleDateFormat FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm");
public static final Locale LOCALE_HUNGARIAN = new Locale("hu", "HU");
public static final TimeZone LOCAL_TIME_ZONE = TimeZone.getTimeZone("Europe/Budapest");
#Override
public void serialize(Calendar value, JsonGenerator gen, SerializerProvider arg2)
throws IOException, JsonProcessingException {
if (value == null) {
gen.writeNull();
} else {
gen.writeString(FORMATTER.format(value.getTime()));
}
}
}
The deserializer class:
public class CustomCalendarDeserializer extends JsonDeserializer<Calendar> {
#Override
public Calendar deserialize(JsonParser jsonparser, DeserializationContext context)
throws IOException, JsonProcessingException {
String dateAsString = jsonparser.getText();
try {
Date date = CustomCalendarSerializer.FORMATTER.parse(dateAsString);
Calendar calendar = Calendar.getInstance(
CustomCalendarSerializer.LOCAL_TIME_ZONE,
CustomCalendarSerializer.LOCALE_HUNGARIAN
);
calendar.setTime(date);
return calendar;
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
and the usage of the above classes:
public class CalendarEntry {
#JsonSerialize(using = CustomCalendarSerializer.class)
#JsonDeserialize(using = CustomCalendarDeserializer.class)
private Calendar calendar;
// ... additional things ...
}
Using this implementation the execution of the serialization and deserialization process consecutively results the origin value.
Only using the #JsonFormat annotation the deserialization gives different result I think because of the library internal timezone default setup what you can not change with annotation parameters (that was my experience with Jackson library 2.5.3 and 2.6.3 version as well).
To add characters such as T and Z in your date
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'")
private Date currentTime;
output
{
"currentTime": "2019-12-11T11:40:49Z"
}
Just a complete example for spring boot application with RFC3339 datetime format
package bj.demo;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import java.text.SimpleDateFormat;
/**
* Created by BaiJiFeiLong#gmail.com at 2018/5/4 10:22
*/
#SpringBootApplication
public class BarApp implements ApplicationListener<ApplicationReadyEvent> {
public static void main(String[] args) {
SpringApplication.run(BarApp.class, args);
}
#Autowired
private ObjectMapper objectMapper;
#Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"));
}
}
Building on #miklov-kriven's very helpful answer, I hope these two additional points of consideration prove helpful to someone:
(1) I find it a nice idea to include serializer and de-serializer as static inner classes in the same class. NB, using ThreadLocal for thread safety of SimpleDateFormat.
public class DateConverter {
private static final ThreadLocal<SimpleDateFormat> sdf =
ThreadLocal.<SimpleDateFormat>withInitial(
() -> {return new SimpleDateFormat("yyyy-MM-dd HH:mm a z");});
public static class Serialize extends JsonSerializer<Date> {
#Override
public void serialize(Date value, JsonGenerator jgen SerializerProvider provider) throws Exception {
if (value == null) {
jgen.writeNull();
}
else {
jgen.writeString(sdf.get().format(value));
}
}
}
public static class Deserialize extends JsonDeserializer<Date> {
#Overrride
public Date deserialize(JsonParser jp, DeserializationContext ctxt) throws Exception {
String dateAsString = jp.getText();
try {
if (Strings.isNullOrEmpty(dateAsString)) {
return null;
}
else {
return new Date(sdf.get().parse(dateAsString).getTime());
}
}
catch (ParseException pe) {
throw new RuntimeException(pe);
}
}
}
}
(2) As an alternative to using #JsonSerialize and #JsonDeserialize annotations on each individual class member you could also consider overriding Jackson's default serialization by applying the custom serialization at an application level, that is all class members of type Date will be serialized by Jackson using this custom serialization without explicit annotation on each field. If you are using Spring Boot for example one way to do this would as follows:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public Module customModule() {
SimpleModule module = new SimpleModule();
module.addSerializer(Date.class, new DateConverter.Serialize());
module.addDeserializer(Date.class, new Dateconverter.Deserialize());
return module;
}
}
If anyone has problems with using a custom dateformat for java.sql.Date, this is the simplest solution:
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(java.sql.Date.class, new DateSerializer());
mapper.registerModule(module);
(This SO-answer saved me a lot of trouble: https://stackoverflow.com/a/35212795/3149048 )
Jackson uses the SqlDateSerializer by default for java.sql.Date, but currently, this serializer doesn't take the dateformat into account, see this issue: https://github.com/FasterXML/jackson-databind/issues/1407 .
The workaround is to register a different serializer for java.sql.Date as shown in the code example.
I want to point out that setting a SimpleDateFormat like described in the other answer only works for a java.util.Date which I assume is meant in the question.
But for java.sql.Date the formatter does not work.
In my case it was not very obvious why the formatter did not work because in the model which should be serialized the field was in fact a java.utl.Date but the actual object ended up beeing a java.sql.Date.
This is possible because
public class java.sql extends java.util.Date
So this is actually valid
java.util.Date date = new java.sql.Date(1542381115815L);
So if you are wondering why your Date field is not correctly formatted make sure that the object is really a java.util.Date.
Here is also mentioned why handling java.sql.Date will not be added.
This would then be breaking change, and I don't think that is warranted. If we were starting from scratch I would agree with the change, but as things are not so much.
Working for me. SpringBoot.
import com.alibaba.fastjson.annotation.JSONField;
#JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
output:
{
"createTime": "2019-06-14 13:07:21"
}
If we are having the spring boot application, then one more option thats simple to implement for app wide configuration is to use below in application properties file. You can customize the format as needed.
spring.jackson.date-format=yyyy-MM-dd'T'HH:mm:ss.SSS
NOTE: If using this solution use the Spring Dependency Injection to get the reference of the ObjectMapper class.
Cons of not using explicit format is sometimes while upgrading the libraries for jackson code breaks because of change in the format for some versions.