Jackson accepting negative dates - java

I am trying to get a date field from JSON in a spring-boot application with Jackson. The JSONFormat looks like this:
#NotNull(message = ValidationErrors.NOT_BLANK_MESSAGE)
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyyMMdd")
private Date date;
It works fine for most of the cases but when I pass 2017-0526, it is automatically converting it to 10th of May, 2018.
I want to throw exception in case the date is not in the yyyyMMdd format or contains minus sign. I tried going through stack overflow and Jackson documentation, but couldn't find anything.
Why is JsonFormat accepting negative dates?
Is there any workaround for this, so that it throws exception when such dates are passed?

This is an issue with the underlying Java class that parses dates. The parser is by default lenient and will parse dates that seem wrong. For stricter parsing you need to set the lenient property to false with the setLenient method. E.g. this setup will result in a InvalidFormatException when parsing a JSON with a date string "2017-0526":
ObjectMapper mapper = new ObjectMapper();
SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
df.setLenient(false);
mapper.setDateFormat(df);
At the moment you can't configure this through a #JsonFormat annotation. There seems to be a plan for that for version 2.9.0. Link to issue at github

I wanted something that will affect the whole (spring-boot) project and came up with this:
#Configuration
public class JsonConfiguration {
#Bean
public Jackson2ObjectMapperBuilderCustomizer customize() {
return builder -> builder
.dateFormat(StdDateFormat.instance.withLenient(false))
.build();
}
}

Related

Using application property in Spring Boot annotation?

I have the following date field in my DTO class:
#JsonFormat(pattern="dd.MM.yyyy")
private LocalDateTime date;
I define the date format in my application.yml as shown below:
spring:
jackson:
date-format: "dd.MM.yyyy"
I am trying to use this format in my DTO field directly like below:
#JsonFormat(pattern="${spring.jackson.date-format}")
private LocalDateTime date;
Is it possible? Or do ı have to add a #Value field like below? I tried but cannot use this dateFormat in my date field.
#Value("${spring.jackson.date-format}")
private String dateFormat;
JsonFormat is not a spring annotation, therefore you can't use spring expression language.
spring.jackson.date-format defines default date format for some types of date classes, you don't have to use this variable inside JsonFormat, just define the value. For details see e.g. https://www.baeldung.com/spring-boot-formatting-json-dates
If you would like to be more flexible in spring you can define converters for any type, see the same article.
You have good tips here: https://www.baeldung.com/spring-boot-formatting-json-dates
Either configure the default format, like
spring.jackson.date-format=dd.MM.yyyy
or configure the serializer:
#Configuration
public class MyJsonConfig {
#Value("${spring.jackson.date-format}")
private String dateFormat;
#Bean
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
return builder -> {
builder.simpleDateFormat(dateTimeFormat);
builder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(dateFormat)));
builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(dateFormat)));
};
}
}

Date format time on Spring Doc swagger API

I'm trying to generate the documentation from my springboot application using spring doc , this is some of the attributes of the class which is causing me issues:
public class user {
#JsonFormat(pattern = "yyyy-MM-dd")
private Date dateOfBirth;
}
With the Spring doc annotation, in the swagger i got this:
dateOfBirth* string($date-time)
"dateOfBirth": "2020-04-29T14:15:32.475Z"
while i would like to have this:
dateOfBirth* string($date)
"dateOfBirth": "2020-04-29"
How to do that? I think to be close to solution but i can't firugre out what i'm missing
I think the answer you are looking for is here: swagger date field vs date-time field
Date is an object DateTime for swagger, as it is really a DateTime object. Use the appropriate type, like LocalDate, they know how to handle that.
By the way, how would you expect Swagger to properly convert a Date Pattern into the appropriate type ? It's like too much magic. Swagger relies on thing that are common practices.
The JSONFormat won't change how swagger interpret your data.

How do I format a Date as a Timestamp in Springboot 2?

Spring boot 2 has made UTC format the default for dates when serializing objects as json. This broke several of our old integrations that relied on the date being a timestamp. How do I selectively restore this functionality to the responses that need it?
On any dates you need formatted as a timestamp again, in either the constructor or on the field annotate them with #JsonFormat(shape = JsonFormat.Shape.NUMBER) like so:
#JsonFormat(shape = JsonFormat.Shape.Number)
private Date myDate;
or
MyClass(#JsonFormat(shape = JsonFormat.Shape.Number)
Date myDate) {
...
}

json date format in spring-boot

I am using spring-boot and I have an entity class defined something like this
import org.joda.time.LocalDateTime;
#Entity
public class Project {
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDateTime")
private LocalDateTime start_date;
...
...
}
When this class is converted to JSON, the field gets converted to the following string representation
{"start_date":[2014,11,15,0,0,0,0],...., ...}
I want to have the json response as yyyy-MM-dd.
I tried the #DateTimeFormat(iso = ISO.DATE) annotation and that did not help either.
Is there an easy way to do this conversion to proper json format ?
There are three things that you need to do to format the date as yyyy-MM-dd:
Add a dependency on com.fasterxml.jackson.datatype:jackson-datatype-joda. Judging by the output you're getting at the moment, I think you may already have this dependency.
Configure Jackson not to format dates as timestamps by adding spring.jackson.serialization.write-dates-as-timestamps: false to your application.properties file.
Annotate the LocalDataTime field or getter method with #JsonFormat(pattern="yyyy-MM-dd")
Note: You'll need to use Spring Boot 1.2 for step 2 to work.
Without additional dependency - the only thing I had to do is:
To take care send date from client as string object, in format yyyy/MM/dd
In Spring Boot application, to add annotation on the date field with
the same format
public class Foo
{
#JsonFormat(pattern = "yyyy/MM/dd")
private Date dueDate;
}
Using Spring Boot 2.3.5 version
Update
Another option, instead of step 2, to modify application.properties file, add there the format for any Date object:
spring.jackson.date-format=yyyy/MM/dd
You can use #JsonFormat annotation in and the desired pattern like this without using any dependency :
#JsonFormat(pattern="yyyy-MM-dd")
private Date created_At;
Took me some time struggling with Spring Boot Application + Date Format for my input so I'll try to resume what I saw.
If your date is argument to a function, you can use #DateTimeFormat(pattern = "yyyy-MM-dd") to define a pattern (ie. org.springframework.format.annotation.DateTimeFormat).
If your date is inside an object argument to the function, you can use #JsonFormat(pattern = "yyyy-MM-dd") to define a pattern (ie. com.fasterxml.jackson.annotation.JsonFormat)
If neither of these works, you can try changing your date Type, for me I had tu use org.joda.time.LocalDate in order to make it work with option 2 :
#JsonFormat(pattern = "dd/MM/yyyy")
private org.joda.time.LocalDate date;

Json response not generated as expected using #JsonCreator andd #JsonProperty

I am using JDK 1.6 , Jackson 2.0.5 , Spring 3.0.3 and using jackson annotations to serialize and deserialize json response.
public class MyDate extends java.sql.Date{
private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM/dd/yyyy");
private String dateString;
#JsonCreator
public MyDate(#JsonProperty("dateString") String date){
super(simpleDateFormat.parse(date).getTime());
dateString = date;
}
public String getDateString(){
return dateString;
}
private final setDateString(String date){
// .....
}
}
I am getting json response message like 1417977000000 , but it should be like 12/08/2014.
Do I need to write anything else also ?
I tried to follow Jackson wiki page article.
EDIT:
On basis of discussion with #Sotirios Delimanolis I tried JsonValue annotation on getter method and it worked.
#JsonValue
public String getDateString(){
return dateString;
}
Your type is a java.sql.Date which is a java.util.Date which is considered special for Jackson. By default, it writes dates (instances of type java.util.Date) as their timestamps. You can disable this with
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
or the corresponding configuration for your version of Jackson.
This, however, will give you something like
"2014-12-08T08:00:00.000+0000"
It will not use your SimpleDateFormat. You can register a DateFormat with the ObjectMapper like so
objectMapper.setDateFormat(new SimpleDateFormat("MM/dd/yyyy"));
The best solution would be to use composition over inheritance. Do not extend java.util.Date directly or indirectly.
If you don't want to use a general solution, you can always set format per property
public class DateStuff {
#JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd,HH:00", timezone="CET")
public Date creationTime;
}
For more information please read here: http://wiki.fasterxml.com/JacksonFAQDateHandling
Edit:
As a side note
(aka "Please do NOT use java.sql.Date, ever!")
Although Jackson supports java.sql.Date, there are known issues with
respect to timezone handling, partly due to design of this class. It
is recommended that this type is avoided, if possible, and regular
java.util.Date (or java.util.Calendar) used instead. If this is not
possible, it may be necessary for applications to convert these dates
using java.util.Calendar and explicit timezone definition.

Categories

Resources