Date format from Android (java) to Spring Boot - java

I'm working with Android Studio (java) to make the front part of my application, and I work with Spring Boot to the back part.
The SQL database uses TimeStamp.
So my problem is that when I send an object from front (Android) to back (Spring) throws an error:
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type java.util.Date from String "Feb 18, 2021 2:47:40 AM": not a valid representation (error: Failed to parse Date value 'Feb 18, 2021 2:47:40 AM': Cannot parse date "Feb 18, 2021 2:47:40 AM": not compatible with any of standard forms ("yyyy-MM-dd'T'HH:mm:ss.SSSX", "yyyy-MM-dd'T'HH:mm:ss.SSS", "EEE, dd MMM yyyy HH:mm:ss zzz", "yyyy-MM-dd")); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type java.util.Date from String "Feb 18, 2021 2:47:40 AM": not a valid representation (error: Failed to parse Date value 'Feb 18, 2021 2:47:40 AM': Cannot parse date "Feb 18, 2021 2:47:40 AM": not compatible with any of standard forms ("yyyy-MM-dd'T'HH:mm:ss.SSSX", "yyyy-MM-dd'T'HH:mm:ss.SSS", "EEE, dd MMM yyyy HH:mm:ss zzz", "yyyy-MM-dd"))
at [Source: (PushbackInputStream); line: 1, column: 123] (through reference chain: com.prueba.dataproviders.model.Solicitud["fecha"])]
So I guess the problem its from Android sending information to Spring, but I don't know how to handle it...
MORE INFORMATION:
This is an example when I send information from Spring to Android:
{
"id": 23,
"fecha": "2021-02-18T02:47:40.000+00:00",
"estadoSolicitud": 1
}
I keep the attribute "fecha" which its a date in a Date variable.
But when I send the same object to back it sends:
{"estadoSolicitud":0,"fecha":"Feb 18, 2021 2:47:40 AM","id":23}
Thank you in advance <3
CODE:
At Spring Solicitud class:
#Entity
#Table(name = "solicitud")
public class Solicitud implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#GenericGenerator(name = "increment", strategy = "increment")
#Column(name = "id")
private int id;
#Column(name = "fecha", insertable = false)
private Date fecha;
#Column(name="estadoSolicitud")
private int estadoSolicitud; // "0 Pendiente, 1 Realizada 2 Rechazada
At Spring the the post method that receives the <Solicitud> object:
#RequestMapping(value = "/solicitudes/gestionarSolicitud/{estadoSol}", method = RequestMethod.POST, produces = "application/json")
public ResponseEntity<Object> setSolicitud(#RequestBody Solicitud solicitud, #PathVariable(value="estadoSol") int estadoSol ){
Optional<Solicitud> optionalSolicitud = solicitudService.gestionarSolicitud(solicitud, estadoSol);
if (optionalSolicitud.isPresent()) {
return new ResponseEntity<Object>(optionalSolicitud.get(), HttpStatus.OK);}
} else {
return new ResponseEntity<Object>(null , HttpStatus.OK);
}
}
At Android (front part) Solicitud Model:
public class Solicitud implements Serializable {
private int id;
private Date fecha;
private int estadoSolicitud; // 0 pendiente 1 Aceptada 2 Rechazada
//getters && setters...
}
At Android the request method that's request the post method to back:
public interface SolicitudService {
#POST("/solicitudes/gestionarSolicitud/{estadoSol}")
Call<Solicitud> gestionarSolitud( #Body Solicitud solicitud, #Path("estadoSol") int estadoSol);
}
At Android the function that uses the request method:
private void gestionarSolicitud(#NotNull Solicitud solicitud, int estadoSol) {
SolicitudService solicitudService = ApiClient.getClient().create(SolicitudService.class);
Call<Solicitud> call = solicitudService.gestionarSolitud(solicitud, estadoSol);
call.enqueue(new Callback<Solicitud>() {
#Override
public void onResponse(Call<Solicitud> call, Response<Solicitud> response) {
Solicitud solActualizada = response.body();
if (solActualizada != null && solActualizada.getEstadoSol() == estadoSol) {
if (estadoSol == 1)
Toast.makeText(context, "Usuario registrado correctamente", Toast.LENGTH_LONG).show();
else if (estadoSol == 2)
Toast.makeText(context, "Solicitud rechazada", Toast.LENGTH_LONG).show();
notifyDataSetChanged();
} else {
Toast.makeText(context, "Ups! Ha ocurrido un error", Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call<Solicitud> call, Throwable t) {
Toast.makeText(context, "Ups! Ha ocurrido un error del servidor.", Toast.LENGTH_LONG).show();
}
});
}

I think you have to try Joda Time library as a common middleware for your date fields.

You haven't shown any actual code, so a definitive answer isn't possible, but you need to make sure that whatever you are using to serialize your java objects to Json on the Android side properly serializes Dates to ISO-8601 format.
Most mainstream Json serializers, e.g. Gson, will do that by default.

The exception is saying that the value you are sending from client side(android) is having different data type, what you are fetching in back-end (Spring).
At both end the datatype must be same.
Please try this
Spring Code : You can mention the date format with JsonFormat annotation
String DATE_FORMAT_MM_DD_YYYY = "MM/dd/yyyy"
#JsonFormat(pattern = DATE_FORMAT_MM_DD_YYYY)
private Date fetching_date;
For Android Code : Get the date and you can change the date formats using below code
You can define the date formats like this :
const val DATE_FORMAT_yyyy_MM_dd_HH_mm_ss_a = "yyyy-MM-dd HH:mm:ss a"
const val DATE_FORMAT_MMM_dd_yyyy = "MMM dd, yyyy"
const val DATE_FORMAT_MMM_dd_yyyy_HH_MM_AA = "MMM dd, yyyy hh:mm aa"
const val DATE_FORMAT_YYYY_MM_DD = "yyyy-MM-dd"
//Convertion of one date format to another
fun convertDateFormat(oldFormat: String, newFormat: String, dateString: String): String {
var sdf = SimpleDateFormat(oldFormat)
try {
val date = sdf.parse(dateString)
sdf = SimpleDateFormat(newFormat, getLocalForDateFormat())
return sdf.format(date)
} catch (e: Exception) {
e.printStackTrace()
}
return ""
}
Send the date from android to back-end in request.

Related

How to parse properly Date string to java.util.Date when deserializing JSON to Java POJO with Jackson ObjectMapper

I am implementing an application that gets the data from certin endponts in json formats and tries to deserialize tem to Java Objects but I have problems with the parsing of the date in the JSON.This is how the Date looks like in the JSON: "/Date(1633122000000+0300)/" and I cannot find information in Google how to successfully parse this format.
{
"Date": "/Date(1633122000000+0300)/",
"Filled": 0,
"Needed": 0,
"Paid": 0
}
This is the pojo I use to deserialize the data to using Jackson ObjectMapper:
import java.util.Date;
#Data
#AllArgsConstructor
#NoArgsConstructor
public class TimeByDateSheet {
#JsonProperty("Date")
#JsonFormat(timezone = "GMT+03:00")
#JsonDeserialize(using = DateDeserializer.class, as=Date.class)
private Date date;
#JsonProperty("Filled")
private Long filled;
#JsonProperty("Needed")
private Long needed;
#JsonProperty("Paid")
private Integer paid;
}
And here is my DateDeserializer:
#SuppressWarnings("serial")
public class DateDeserializer extends JsonDeserializer<Date> {
#Override
public Date deserialize(JsonParser jsonParser, DeserializationContext context)
throws IOException, JsonProcessingException {
SimpleDateFormat simpleDateFormat =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzz", Locale.getDefault());
String dateStr = jsonParser.getText();
Date date;
try{
date = simpleDateFormat.parse(dateStr);
}catch(ParseException e){
throw new RuntimeException(e);
}
return date;
}
}
But it does not work correctly. I get the following exception:
Connected to the target VM, address: '127.0.0.1:52760', transport: 'socket'
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: java.text.ParseException: Unparseable date: "/Date(1633035600000+0300)/" (through reference chain: java.util.ArrayList[0]->com.dataart.forecasts.pojo.timebydate.TimeByDateSheet["Date"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:392)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:351)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1821)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:315)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:176)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:355)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:244)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:28)
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4675)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3630)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3613)
at com.dataart.forecasts.DataProcessor.deserializeTimeByDateSheetsList(DataProcessor.java:198)
at com.dataart.forecasts.ForecastReportApplication.main(ForecastReportApplication.java:50)
Caused by: java.lang.RuntimeException: java.text.ParseException: Unparseable date: "/Date(1633035600000+0300)/"
at com.dataart.forecasts.DateDeserializer.deserialize(DateDeserializer.java:28)
at com.dataart.forecasts.DateDeserializer.deserialize(DateDeserializer.java:16)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:313)
... 10 more
Caused by: java.text.ParseException: Unparseable date: "/Date(1633035600000+0300)/"
at java.base/java.text.DateFormat.parse(DateFormat.java:395)
at com.dataart.forecasts.DateDeserializer.deserialize(DateDeserializer.java:26)
... 13 more
Could someone help me, please. I searched a lot in internet but could not find a solution.
Thank you in advance! :)
It looks like there is a problem generating the JSON. I really don't think you want to have the dates formatted like that. Right now, you have some odd text surrounding a unix timestamp in milliseconds followed by a zone offset. You are also using the old and rather frowned-upon Date and SimpleDateFormat classes rather than the newer java.time API. However, it is possible to deserialize your date format. Here is one way:
public class DateDeserializer extends JsonDeserializer<Date> {
#Override
public Date deserialize(JsonParser jsonParser, DeserializationContext context)
throws IOException, JsonProcessingException {
Pattern pattern = Pattern.compile("/Date\\((\\d+)([+-]\\d+)\\)/");
Matcher matcher = pattern.matcher(jsonParser.getText());
if (matcher.find()) {
String timestamp = matcher.group(1);
String offset = matcher.group(2);
Instant instant = Instant.ofEpochMilli(Long.parseLong(timestamp));
ZonedDateTime zdt = instant.atZone(ZoneId.of(offset));
instant = zdt.toInstant();
return Date.from(instant);
} else {
throw new RuntimeException("Invalid format: " + jsonParser.getText());
}
}
}
java.time
For this answer I am assuming:
The time in your JSON may come with or without the UTC offset.
You can go all-in on java.time, the modern Java date and time API, and declare your variable to be of type Instant or OffsetDateTime, for example (not Date).
For JSON that comes with an offset such as +0300 declare your variable an OffsetDateTime. Then use the following deserializer.
public class OdtDeserializer extends JsonDeserializer<OffsetDateTime> {
private static final DateTimeFormatter JSON_DATE_FORMATTER = new DateTimeFormatterBuilder()
.appendLiteral("/Date(")
.appendValue(ChronoField.INSTANT_SECONDS)
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
.appendOffset("+HHMM", "Z")
.appendLiteral(")/")
.toFormatter();
#Override
public OffsetDateTime deserialize(JsonParser jsonParser, DeserializationContext context)
throws IOException {
String dateStr = jsonParser.getText();
return OffsetDateTime.parse(dateStr, JSON_DATE_FORMATTER);
}
}
For JSON that comes without offset like /Date(1636510000000)/ declare your variable Instant. Use a similar deserializer. Leave out the offset from the formatter. Parse into an Instant — the syntax is a bit different.
public class InstantDeserializerWIthoutOffset extends JsonDeserializer<Instant> {
private static final DateTimeFormatter JSON_DATE_FORMATTER = new DateTimeFormatterBuilder()
.appendLiteral("/Date(")
.appendValue(ChronoField.INSTANT_SECONDS)
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
.appendLiteral(")/")
.toFormatter();
#Override
public Instant deserialize(JsonParser jsonParser, DeserializationContext context)
throws IOException {
String dateStr = jsonParser.getText();
return JSON_DATE_FORMATTER.parse(dateStr, Instant::from);
}
}
For JSON that may come with or without the offset still use Instant and just modify the formatter of the latter deserializer to include an optional offset:
private static final DateTimeFormatter JSON_DATE_FORMATTER = new DateTimeFormatterBuilder()
.appendLiteral("/Date(")
.appendValue(ChronoField.INSTANT_SECONDS)
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
.optionalStart()
.appendOffset("+HHMM", "Z")
.optionalEnd()
.appendLiteral(")/")
.toFormatter();
If you cannot modify your POJO class and need to stay with Date, modify my Instant deserializer into a Date deserializer by changing the declaration and returning a Date like this:
String dateStr = jsonParser.getText();
Instant inst = JSON_DATE_FORMATTER.parse(dateStr, Instant::from);
return Date.from(inst);
Final solution catching both: /Date(1633035600000+0300)/ and /Date(-62135596800000)/ (the latter was also present at one place in oneof the JSONs). Thank you #DavidConrad
#Override
public Date deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException, JsonProcessingException {
String dateString = jsonParser.getText();
Pattern pattern = Pattern.compile("/Date\\((-)?(\\d+)([+-]\\d+)?\\)/");
Matcher matcher = pattern.matcher(dateString);
if (!matcher.find()) {
throw new RuntimeException("Invalid format: " + dateString);
}
String timestamp = matcher.group(2);
String offset = matcher.group(3);
Instant instant = Instant.ofEpochMilli(Long.parseLong(timestamp));
if (nonNull(offset)) {
ZonedDateTime zdt = instant.atZone(ZoneId.of(offset));
instant = zdt.toInstant();
}
return Date.from(instant);
}
#DavidConrad Thank you, I will try your solution.
By the way, for now I made a workaround that works for me for now:
#Override
public Date deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException, JsonProcessingException {
SimpleDateFormat dateFormattter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr = jsonParser.getText();
String timeZone = dateStr.substring(dateStr.indexOf("+") + 1, dateStr.indexOf(")"));
String timeZoneShift = String.format("%s:%s",
timeZone.substring(0, timeZone.length()/2),
timeZone.substring(timeZone.length()/2));
dateFormattter.setTimeZone(TimeZone.getTimeZone(String.format("GMT+%s", timeZoneShift)));
Long millis = 0L;
if (dateStr.contains("+") && !dateStr.contains("-")) {
millis = Long.parseLong(dateStr.substring(dateStr.indexOf("(") + 1, dateStr.indexOf("+")));
} else if (dateStr.contains("+") && !dateStr.contains("-")) {
millis = Long.parseLong(dateStr.substring(dateStr.indexOf("(") + 1, dateStr.indexOf(")")));
}
Date date = new Date(millis);
String stringDate= dateFormattter.format(date);
try {
date = dateFormattter.parse(stringDate);
} catch (ParseException e) {
throw new RuntimeException(e);
}
return date;
}

How to enforce a date value input in a REST API?

The user needs to make a POST to /api/date with something like March 13, 2019 or 08/19/2020. As long as it's a date, it should be accepted.
I have something like this (Using Dropwizard framework)
#POST
public void post(String date)
{
validateDate(date);
//continue
}
private void validateDate(String date)
{
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
try
{
LocalDateTime.parse(date, formatter);
}
catch (DateTimeParseException e)
{
//not a date
}
}
I'm not sure if I'm in the right approach, there must be a better way to validate strings as dates.
You can accept multiple formats for a date time using the optional syntax ([<your format>])*. eg
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
"[yyyy-MM-dd][dd-MM-yyyy][MMMM dd, yyyy]");
EDIT: It is not really clear if you want to know how to validate dates correctly or how to handle invalid inputs to your REST API. My answer shows the latter.
You should use a return value for your post method. You can return javax.ws.rs.core.Response, with that you can control the HTTP code and response object you want to return.
On success, you would normally return the created object with a 200 success code.
On failure, you would return an error code (like 400 Bad request) with a detailed error message ("Date must be in the format yyyy-MM-dd").
To create the response, you can use the ResponseBuilder.
Example:
Response.ok( yourObject ).build(); //success
Response.status( Status.BAD_REQUEST ).entity( yourErrorMessageObject ).build(); // failure
So I would change the code to this:
#POST
public Response post(String date)
{
if(!isDateValid(date)){
return Response.status( Status.BAD_REQUEST ).entity( buildErrorMessage()).build();
}
//continue
Response.ok().build(); // returns nothing on success (like void)
}
private boolean isDateValid(String date)
{
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
try
{
LocalDateTime.parse(date, formatter);
return true;
}
catch (DateTimeParseException e)
{
//not a date
return false;
}
}

Cannot save datetime to MongoDB using Spring Boot

I use Spring Boot and I try to save some date in MongoDB. My input date is
"2017-08-14T12:59"
I get this error while saving:
Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Failed to parse Date value '2017-08-14T12:59': Can not parse date "2017-08-14T12:59.000Z": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSS'Z'', parsing fails (leniency? null); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Failed to parse Date value '2017-08-14T12:59': Can not parse date "2017-08-14T12:59.000Z": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSS'Z'', parsing fails (leniency? null) (through reference chain:
In my POJO i tried like this:
#JsonDeserialize(using= CustomDateDeserialize.class)
private Date inputDateTime;
and I've implemented Deserializer like this :
private SimpleDateFormat dateFormat = new SimpleDateFormat(
"yyyy-MM-dd HH:mm");
#Override
public Date deserialize(JsonParser paramJsonParser,
DeserializationContext paramDeserializationContext)
throws IOException, JsonProcessingException {
String str = paramJsonParser.getText().trim();
try {
return dateFormat.parse(str);
} catch (ParseException e) {
}
return paramDeserializationContext.parseDate(str);
}
What else I miss here? Any help appreciated.
you need to modify format in your deserializer.
SimpleDateFormat dateFormat = new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm");
any way simpledatetimeformat is not thread safe. if you java8 use DateTimeFormat.
Why don't you try Instant library
#Field("your_db_id_name")
private Instant inputDateTime;
public void setInputDateTime(Instant inputDateTime) {
this.inputDateTime = inputDateTime;
}
public void getInputDateTime() {
return inputDateTime;
}
You can set Filed by using Instant.now()

Doing timezone conversion while using BeanUtils.copyProperties

I have a Hibernate mapped model class as follows,
#Entity
#Table(name = "USER")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "User_SEQ")
#SequenceGenerator(sequenceName = "User_SEQ", allocationSize = 1, name = "User_SEQ")
private Integer id;
private Date createdOn;
}
I have another model class as follows which I use for the response from a REST API. The object of this class essentially gets serialized into JSON
public class UserDTO {
private Integer id;
private Date createdOn;
}
Since the variable names are the same, I am using BeanUtils.copyProperties to copy the value of all fields from User to UserDTO (Currently showing only 2 fields above for simplicity)
Data is stored in GMT in the database, hence the createdOn field contains the TIMESTAMP in GMT. I want to return the Date in local time zone e.g. "Europe/Copenhagen". For this I am using the following code (using apache commons),
java.util.Date defaultValue = null;
DateConverter dateConverter = new DateConverter(defaultValue);
dateConverter.setTimeZone(TimeZone.getTimeZone("Europe/Copenhagen"));
BeanUtilsBean beanUtilsBean = BeanUtilsBean.getInstance();
beanUtilsBean.getConvertUtils().register(dateConverter, java.util.Date.class);
BeanUtils.copyProperties(userDTO, user);
The code executes, but userDTO still contains the date in GMT. time zone conversion is not working. What am I missing here?
EDIT1:
I have tried checking by manually passing a date as follows,
#Test
public void testBeanUtilsDateConverter() throws Exception {
System.out.println("\ntestBeanUtilsDateConverter - Start");
Date date = new GregorianCalendar(2014, Calendar.FEBRUARY, 11, 18, 30, 10).getTime();
Date newDate = new Date();
DateConverter converter = new DateConverter();
converter.setTimeZone(TimeZone.getTimeZone("Europe/Copenhagen"));
BeanUtilsBean beanUtilsBean = BeanUtilsBean.getInstance();
beanUtilsBean.getConvertUtils().deregister(java.util.Date.class);
beanUtilsBean.getConvertUtils().register(converter, java.util.Date.class);
System.out.println(newDate);
BeanUtils.copyProperties(newDate, date);
System.out.println(date);
System.out.println(newDate);
System.out.println("testBeanUtilsDateConverter - End");
}
Output:
testBeanUtilsDateConverter - Start
Fri Jun 02 14:04:08 IST 2017
Tue Feb 11 18:30:10 IST 2014
Tue Feb 11 18:30:10 IST 2014
testBeanUtilsDateConverter - End
So the BeanUtils is definitely copying the date to the target, but the converter is either not getting called or not doing anything for some reason
EDIT2 - Using Custom Converter
class MyDateConverter implements Converter {
public MyDateConverter() {
System.out.println("Instantiating MyDateConverter");
}
#Override
public Object convert(Class Date, Object value) {
System.out.println("Inside convert()");
if (value == null) {
System.out.println("Value is null");
return (Date) null;
} else {
System.out.println("Doing date conversion");
Date date = new GregorianCalendar(2015, Calendar.JANUARY, 12, 9, 45, 15).getTime();
return date;
}
}
}
#Test
public void testCustomDateConverter() throws Exception {
System.out.println("\ntestCustomDateConverter - Start");
Date date = new GregorianCalendar(2014, Calendar.FEBRUARY, 11, 18, 30, 10).getTime();
Date newDate = new Date();
BeanUtilsBean beanUtilsBean = BeanUtilsBean.getInstance();
beanUtilsBean.getConvertUtils().deregister(java.util.Date.class);
beanUtilsBean.getConvertUtils().register(new MyDateConverter(), java.util.Date.class);
System.out.println(newDate);
BeanUtils.copyProperties(newDate, date);
System.out.println(date);
System.out.println(newDate);
System.out.println("testCustomDateConverter - End");
}
Output:
testCustomDateConverter - Start
Instantiating MyDateConverter
Fri Jun 02 14:04:09 IST 2017
Tue Feb 11 18:30:10 IST 2014
Tue Feb 11 18:30:10 IST 2014
testCustomDateConverter - End
Again the same result. The custom converter is getting instantiated, but the convert method is not called. I even tried a custom Long converter to check if it's something to do with using the Date class, but even that was not getting called. There is something missing in the registration part that BeanUtils is not able to call the overridden convert function.

How to accept Date params in a GET request to Spring MVC Controller?

I've a GET request that sends a date in YYYY-MM-DD format to a Spring Controller.
The controller code is as follows:
#RequestMapping(value="/fetch" , method=RequestMethod.GET)
public #ResponseBody String fetchResult(#RequestParam("from") Date fromDate) {
//Content goes here
}
The request is sent correctly as I'm checking with Firebug.
I get the error:
HTTP Status 400: The request sent by the client was syntactically incorrect.
How can I make the controller accept this format of Date?
Please help. What am I doing wrong?
Ok, I solved it.
Writing it for anyone who might be tired after a full day of non-stop coding & miss such a silly thing.
#RequestMapping(value="/fetch" , method=RequestMethod.GET)
public #ResponseBody String fetchResult(#RequestParam("from") #DateTimeFormat(pattern="yyyy-MM-dd") Date fromDate) {
//Content goes here
}
Yes, it's simple. Just add the DateTimeFormat annotation.
This is what I did to get formatted date from front end
#RequestMapping(value = "/{dateString}", method = RequestMethod.GET)
#ResponseBody
public HttpStatus getSomething(#PathVariable #DateTimeFormat(iso = DateTimeFormat.ISO.DATE) String dateString) {
return OK;
}
You can use it to get what you want.
... or you can do it the right way and have a coherent rule for serialisation/deserialisation of dates all across your application. put this in application.properties:
spring.mvc.date-format=yyyy-MM-dd
Below solution perfectly works for spring boot application.
Controller:
#GetMapping("user/getAllInactiveUsers")
List<User> getAllInactiveUsers(#RequestParam("date") #DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") Date dateTime) {
return userRepository.getAllInactiveUsers(dateTime);
}
So in the caller (in my case its a web flux), we need to pass date time in this("yyyy-MM-dd HH:mm:ss") format.
Caller Side:
public Flux<UserDto> getAllInactiveUsers(String dateTime) {
Flux<UserDto> userDto = RegistryDBService.getDbWebClient(dbServiceUrl).get()
.uri("/user/getAllInactiveUsers?date={dateTime}", dateTime).retrieve()
.bodyToFlux(User.class).map(UserDto::of);
return userDto;
}
Repository:
#Query("SELECT u from User u where u.validLoginDate < ?1 AND u.invalidLoginDate < ?1 and u.status!='LOCKED'")
List<User> getAllInactiveUsers(Date dateTime);
Cheers!!
If you want to use a PathVariable, you can use an example method below (all methods are and do the same):
//You can consume the path .../users/added-since1/2019-04-25
#GetMapping("/users/added-since1/{since}")
public String userAddedSince1(#PathVariable("since") #DateTimeFormat(pattern = "yyyy-MM-dd") Date since) {
return "Date: " + since.toString(); //The output is "Date: Thu Apr 25 00:00:00 COT 2019"
}
//You can consume the path .../users/added-since2/2019-04-25
#RequestMapping("/users/added-since2/{since}")
public String userAddedSince2(#PathVariable("since") #DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date since) {
return "Date: " + since.toString(); //The output is "Date: Wed Apr 24 19:00:00 COT 2019"
}
//You can consume the path .../users/added-since3/2019-04-25
#RequestMapping("/users/added-since3/{since}")
public String userAddedSince3(#PathVariable("since") #DateTimeFormat(pattern = "yyyy-MM-dd") Date since) {
return "Date: " + since.toString(); //The output is "Date: Thu Apr 25 00:00:00 COT 2019"
}
You can use :
public #ResponseBody String fetchResult(#RequestParam("from")#DateTimeFormat(pattern="yyyy-MM-dd") Date fromDate) {
//Your code...
}
2000-10-31T01:30:00.000-05:00 convert to Datetime (Joda)
#GetMapping("test/{dateTimeStart}")
public void getCheckDaily2(
#PathVariable(value = "dateTimeStart", required = false)
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
DateTime dateTimeStart){
body here...
}

Categories