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;
}
}
Related
I am providing a date input in MM/dd/yyyy format, the format produces an incorrect date on UI, this only happens with MM/dd/yyyy format, however, it is working fine if input will be in dd/MM/yyyy.
eg: if today's date 04/08/2020, then it is rendered as 07/09/2021, which is of course wrong date
The application using extjs3 as frontend and so the date picker.
function insSKUDate(element,textElement,img){
var selectHandler = function(myDP, date) {
var field = document.getElementById(textElement);
field.value = date.format('m/d/Y');
field.text = date.format('m/d/Y');
dateField = document.getElementById(textElement);
myDP.hide();
};
var myDP = new Ext.DatePicker(
{
startDay: 1,
minDate: new Date(),
listeners: {
'select':selectHandler
}
}
);
var innerdata = document.getElementById(element);
innerdata.innerHTML="";
myDP.render(element);
var clickHandler = function() {
myDP.show();
};
Ext.EventManager.on(img.id, 'click', clickHandler);
}
somewhere in HTML form
<td width="20%">
<input type="text" class="textbox"
value="<s:property value='skulaunchDate'/>"
name="skulaunchDate"
id="skulaunchDate" readonly="readonly"/>
<img style="vertical-align:text-bottom" src="images/calimg.jpg"
width="16" height="16"
onClick="insSKUDate('skulaunchDateSpan', 'skulaunchDate', this)"
id="skulaunchDateIcon"/>
<span id="skulaunchDateSpan"
style="position:absolute;z-index:1;width:50px;"></span>
<div id="skulaunchDateErrorMsg" align="left"
style="color:#FF0000"/>
</td>
Somewhere in my Struts' execute()
public String getSkulaunchDate() {
return skulaunchDate;
}
public void setSkulaunchDate(String skulaunchDate) {
this.skulaunchDate = skulaunchDate;
}
if (bean.getSkulaunchDate() != null)
setSkulaunchDate(dateUtil.getSQLDateToString(bean.getSkulaunchDate(), "MM/dd/yyyy"));//Replace dd/MM/yyyy to MM/dd/yyyy
// setSkulaunchDate(getSkuLaunchDateStrFormat(bean,dateUtil));//Replace dd/MM/yyyy to MM/dd/yyyy
System.out.println("3.getSkulaunchDate----"+ getSkulaunchDate());
setContactPersonName(bean.getContactPersonName());
setContactPersonPosition(bean.getContactPersonPosition());
setContactPersonEmail(bean.getContactPersonEmail());
setContactPersonNumber(bean.getContactPersonNumber());
setRemarks(bean.getRemarks());
setTpRemarks(bean.getTpRemarks());
try {
if(request_bean.getRequestDate() != null){
setRequest_date(dateUtil.getUtilDateToString(request_bean.getRequestDate(), "MM/dd/yyyy"));//Replace dd/MM/yyyy to MM/dd/yyyy
}
} catch (Exception ex) {
logger.error(ex.getStackTrace());
}
I have doubt on the below method, but it looks fine
public String getSQLDateToString(java.sql.Date date, String format) {
String result = null;
try {
result = new SimpleDateFormat(format).format(date);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
It is found that the input is in SQL date having some problem while parsing, apart from this util date is working fine.
please suggest me the solution to rectify this.
The legacy date-time API is known to be confusing and error-prone. Since you are using Java-7, unfortunately, either you will have to live with it or you can backport the code using modern date-time API to Java-7 using ThreeTen-Backport library.
I recommend you address the following problems with your code:
Never use a date-time parsing/formatting API without a Locale.
If your method can not handle an exception (i.e. can not do something to recover from the failure), it should simply throw the exception so that the calling method can get an opportunity to handle it appropriately. Therefore, using e.printStackTrace() in your method, getSQLDateToString is a bad idea. By the way, SimpleDateFormat#format does not throw an exception. Probably, you got confused with SimpleDateFormat#parse which throws ParseException.
The following code incorporates these comments:
import java.text.SimpleDateFormat;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
// Today
java.sql.Date date = new java.sql.Date(System.currentTimeMillis());
System.out.println(getSQLDateToString(date, "MM/dd/yyyy"));
System.out.println(getSQLDateToString(date, "dd/MM/yyyy"));
}
public static String getSQLDateToString(java.sql.Date date, String format) {
return new SimpleDateFormat(format, Locale.ENGLISH).format(date);
}
}
Output:
02/07/2021
07/02/2021
Using the modern date-time API
Use java.sql.Date#toLocalDate to convert a java.sql.Date to LocalDate.
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
// Today
java.sql.Date date = new java.sql.Date(System.currentTimeMillis());
System.out.println(getSQLDateToString(date, "MM/dd/yyyy"));
System.out.println(getSQLDateToString(date, "dd/MM/yyyy"));
}
public static String getSQLDateToString(java.sql.Date date, String format) {
LocalDate localDate = date.toLocalDate();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(format, Locale.ENGLISH);
return dtf.format(localDate);
}
}
Output:
02/07/2021
07/02/2021
Learn about the modern date-time API from Trail: Date Time.
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()
In my REST API Controller with #PathVariable("timestamp) I have to validate that timestamp format is complaint with ISO 8601 standard: eg. 2016-12-02T18:25:43.511Z.
#RequestMapping("/v3/testMe/{timestamp}")
public class TestController {
private static final String HARDCODED_TEST_VALUE = "{\n\t\"X\": \"01\",\n\t\"Y\": \"0.2\"\n}";
#ApiOperation(nickname = "getTestMe", value = "Return TestMe value", httpMethod = "GET",
authorizations = {#Authorization(value = OAUTH2,
scopes = {#AuthorizationScope(scope = DEFAULT_SCOPE, description = SCOPE_DESCRIPTION)})})
#RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public String getTestMe(#PathVariable("timestamp") String timestamp) {
if (timestamp != null) {
return HARDCODED_TEST_VALUE;
}
throw new ResourceNotFoundException("wrong timestamp format");
}
}
The way of how I would like to achieve it is similiar to above if-else statement that check whether timestamp is null or not - so analogically I would like to add similiar if-else to validate format of timestamp and return body if so or 404 error code if it's not.
Any idea what I could use to do that and please give me ready example ? I've tried simple validation with regex but is not convenient and unfortunately didn't work anyway ...
You can use Java 8's DateTimeFormatter and make sure it parses the string without throwing an exception. Here's a method that that returns true if the input string is a valid ISO date:
boolean isValidIsoDateTime(String date) {
try {
DateTimeFormatter.ISO_DATE_TIME.parse(date);
return true;
} catch (DateTimeParseException e) {
return false;
}
}
To return the hardcoded test value in response body, you should use the method like this:
public String getTestMe(#PathVariable("timestamp") String timestamp) {
if (timestamp != null && isValidIsoDateTime(timestamp)) {
return HARDCODED_TEST_VALUE;
}
throw new ResourceNotFoundException("wrong timestamp format");
}
public class MyClass {
public static void main(String args[]) {
System.out.println("-------------OK--------------");
String inputTimeString = "makara_kann";
if (!inputTimeString.matches("^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$")){
System.out.println("Invalid time string: " + inputTimeString);
} else {
System.out.println("valid time string: " + inputTimeString);
}
}
}
-------------OK--------------
Invalid time string: makara_kann
Am unable to convert string to Joda LocalTime with DefaultFormattingConversionService.
If I pass time as "12:00" it says time is too short, but if I pass it as "12:00:00", it says it is malformed.
import org.joda.time.LocalTime;
import org.springframework.format.support.DefaultFormattingConversionService;
public class SpringLocalTimeFormatterTry {
public static void main(String[] args) {
DefaultFormattingConversionService service = new DefaultFormattingConversionService();
try {
System.out.println(service.convert("12:00", LocalTime.class));
}
catch (Exception e) {
System.out.println(e.getMessage());
}
try {
System.out.println(service.convert("12:00:00", LocalTime.class));
}
catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
How to use it correctly or fix?
The vanilla settings of DefaultFormattingConversionService use platform default locale, which, I assume from the error, are the same as mine, ie. English. That means, that for time you need to add the AM/PM indicator. This works for me:
System.out.println(service.convert("10:12 am", LocalTime.class));
>> 10:12:00.000
To handle your desired time format, you can add an extra converter:
service.addConverter(new Converter<String, LocalTime>() {
#Override
public LocalTime convert(String source) {
return LocalTime.parse(source);
}
});
Then, both examples pass:
System.out.println(service.convert("12:00", LocalTime.class));
>> 12:00:00.000
System.out.println(service.convert("12:00:00", LocalTime.class));
>> 12:00:00.000
You can skip registering the default converters by creating the service with
new DefaultFormattingConversionService(false);
Finally, I assume in the production code you are actually getting the ConversionService from the ConversionServiceFactoryBean, so you can configure that as follows:
#Bean
public ConversionServiceFactoryBean conversionService() {
ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
Set<Converter<?, ?>> myConverters = new HashSet<>();
myConverters.add(new Converter<String, LocalTime>() {
#Override
public LocalTime convert(String source) {
return LocalTime.parse(source);
}
});
conversionServiceFactoryBean.setConverters(myConverters);
return conversionServiceFactoryBean;
}
Try this:
DateTimeFormatter dtf = DateTimeFormat.forPattern("HH:mm:ss");
LocalTime localTime = dtf.parseLocalTime("12:00:00");
System.out.println("Time"+localTime);
I am currently writing a parser for a simple XML. The XML at its longest contains 18 lines. I am trying to parse it and convert it to a POJO. I know that I can use JAXB or similar libraries, but I felt that considering the size of the XML, that would be an overkill. Also, this is an exercise to think beyond libraries.
An example XML would be:
<machineinfo>
<processorCount>4</processorCount>
<boughtDate>2014-06-09 23:17:49.0</boughtDate>
<installationStatus>COMPLETE</installationStatus>
<machineType>BASIC</machineType>
<osVersion>1849AB48DOED</osVersion>
<serverName>fjv920dk</serverName>
<machineStatus>UP</machineStatus>
<statusPay1>NA</statusPay1>
<statusPay2>NA</statusPay2>
<errorCode>NO_ERROR</errorCode>
<exceptionCode>0</exceptionCode>
<isCloneable>true</isCloneable>
<latestVersion>1849AB48DOED</latestVersion>
<mastermachineName/>
<podName>8D2</podName>
<machineName>machine2</machineName>
</machineinfo>
My core conversion logic is as follows:
if (tagName.equalsIgnoreCase("processorCount")) {
machineInfo.setProcessorCount(new Integer(data).intValue());
} else if (tagName.equalsIgnoreCase("boughtDate")) {
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS");
DateTime dt = formatter.parseDateTime(data);
machineInfo.setBoughtDate(dt);
} else if (tagName.equalsIgnoreCase("installationStatus") {
machineInfo.setInstallationStatus(InstallationStatus.valueOf(data));
} else if (tagName.equalsIgnoreCase("installationStatus") {
machineInfo.setInstallationStatus(InstallationStatus.valueOf(data));
}
As you can see, this leads to multiple if conditions. I tried simplifying that by using a Map as follows:
Map <String, Object> map = new HashMap<String, Object>();
map.put("machineName", data);
map.put("machineType", data);
String mapValue = (String) map.get(tagName);
But how do I determine which setter in machineInfo should be invoked?
You should use Java Reflection or Java Beans API for that.
I like to invoke dynamic setters using PropertyDescriptor:
Method writerMethod = new PropertyDescriptor(fieldName, MachineInfo.class).getWriteMethod();
writerMethod.invoke(machineInstance, fieldValue);
Refer to http://docs.oracle.com/javase/7/docs/api/java/beans/PropertyDescriptor.html
Regards,
Bruno
I solved this by using the following snippet:
ConvertUtilsBean convertUtilsBean = new ConvertUtilsBean();
convertUtilsBean.deregister(DateTime.class);
convertUtilsBean.register(new JodaDateTimeConverter(), DateTime.class);
BeanUtilsBean beanUtilsBean = new BeanUtilsBean(convertUtilsBean, new PropertyUtilsBean());
try {
beanUtilsBean.setProperty(machineInfo, qName, temp);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
And by creating the following converter:
class JodaDateTimeConverter implements Converter {
/* (non-Javadoc)
* #see org.apache.commons.beanutils.Converter#convert(java.lang.Class, java.lang.Object)
*/
#SuppressWarnings("unchecked")
public <T> T convert(Class<T> arg0, Object arg1) {
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS");
DateTime dt = formatter.parseDateTime((String) arg1);
return (T) dt;
}
}