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
Related
I know that in Java a method can return only one return type... But if there is any possiblity to this, kindly let me know. From the below method I am trying to return a list if condition satisfies else i am trying to return an error message.
Here is my code:
#RequestMapping(value = "/getcompanies", method = RequestMethod.POST)
public List<CompanyMaster> getCompanies(#RequestBody UserDetails user) {
String OrgLoginId = user.getOrgLoginId();
String password = user.getuPassword();
String checkLoginId = null;
String uPassword = null;
String encPassword = null;
String loginId = null;
String checkAuthorized = null;
// String loginId=userService.getLoginId(OrgLoginId);
List<Object[]> CheckIdPassword = userService.checkLoginId(OrgLoginId);
List<Object[]> results = CheckIdPassword;
for (Object[] obj : results) {
checkLoginId = obj[0].toString();
if (null == obj[1]) {
uPassword = "";
} else {
uPassword = obj[1].toString();
}
loginId = obj[2].toString();
}
checkAuthorized = loginId.substring(0, 3);
if (null != password) {
MD5 md5 = new MD5();
encPassword = md5.getPassword(password);
}
if (checkLoginId == null) {
return "Incorrect loginId..Please enter valid loginId";
} else if (encPassword.equals(uPassword)) {
if (checkAuthorized.equals("STE")) {
List<CompanyMaster> companyList = userService.getCompanyList(OrgLoginId);
return companyList;
} else {
return "You are not Authorized";
}
} else {
return "Incorrect Password";
}
Yes its possible, create a custom Exception say 'MyAppException' and throw that exception with the error message you want.
Write your logic in a try{}catch block and throw the exception in catch so that the response has the error message
public List<CompanyMaster> getCompanies(#RequestBody UserDetails user) throws MyAppppException
{
try
{
//your logic which throws error
return companyList;
}
catch( final MyAppException we )
{
throw new MyAppException("User not found", HttpStatus.NOT_FOUND);
}
}
Refer this link
https://www.codejava.net/java-core/exception/how-to-create-custom-exceptions-in-java
You can achieve this by creating a new presenter Class which contains List and status of type String and change the return type of getCompanies method to presenter class like
public CompaniesPresenter getCompanies()
And your CompaniesPresenter class should look like
public class CompaniesPresenter {
private List<CompanyMaster> companyMaster;
private string status;
//default constructor
public CompaniesPresenter(){
}
//parameterized constructor to return only string in exception case
public CompaniesPresenter(Stirng status){
this.status = status;
}
//parametirized constructor to return success case
public CompaniesPresenter(List<CompanyMaster> companyMaster, Stirng status){
this.companyMaster = companyMaster;
this.status = status;
}
//getters and setters
}
This is how your updated method lokks like
#RequestMapping(value = "/getcompanies", method = RequestMethod.POST)
public CompaniesPresenter getCompanies(#RequestBody UserDetails user) {
String OrgLoginId = user.getOrgLoginId();
String password = user.getuPassword();
String checkLoginId = null;
String uPassword = null;
String encPassword = null;
String loginId = null;
String checkAuthorized = null;
// String loginId=userService.getLoginId(OrgLoginId);
List<Object[]> CheckIdPassword = userService.checkLoginId(OrgLoginId);
List<Object[]> results = CheckIdPassword;
for (Object[] obj : results) {
checkLoginId = obj[0].toString();
if (null == obj[1]) {
uPassword = "";
} else {
uPassword = obj[1].toString();
}
loginId = obj[2].toString();
}
checkAuthorized = loginId.substring(0, 3);
if (null != password) {
MD5 md5 = new MD5();
encPassword = md5.getPassword(password);
}
if (checkLoginId == null) {
return new CompaniesPresenter("Incorrect loginId..Please enter valid loginId");
} else if (encPassword.equals(uPassword)) {
if (checkAuthorized.equals("STE")) {
List<CompanyMaster> companyList = userService.getCompanyList(OrgLoginId);
return new CompaniesPresenter(companyList,"success");
} else {
return new CompaniesPresenter("You are not Authorized");
}
} else {
return new CompaniesPresenter("Incorrect Password");
}
This is not tested please make sure for any compilation errors
vavr's Either class would be a good choice.
The usage of custom exception is most reasonable solution. However, creating custom exception for just one case is not ideal always.
Another solution is to return empty List from your method, check if the List is empty in your servlet (or wherever you are invoking this method from), and show error message there.
It seems like you want to return multiple error messages for different cases. In this case, custom exception is recommended solution. If you don't like custom exceptions, you can return List<Object> and populate error message as the first element in the list. In the place where this List is obtained, check if the first element is instanceOf String or CompanyMaster. Based on what it is, you can perform your operations. This is a weird but possible solution (only if you don't like custom exceptions).
You need to understand the problem first. You are mixing two things here, first authorization, does the user has correct privileges to get company details, second giving the company details itself. Let's understand the first problem when a user tries to access "/getcompanies" endpoint will you let him in if does not have access, in REST world your security model should take care of it. I would use spring security to achieve this. My recommendation would be to explore on "interceptor" and solve the problem of invalid user. This will make your other problem easy as your "/getcompanies" endpoint can focus only on getting the details and return it (SRP).
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;
}
}
I am using grails 2.4.2. I have a domain as JointMemberInvestment where I have an instance of JointMember class. But when I want to save the data it gives me the following error:
Could not find matching constructor for: somiti.JointMember(java.lang.String).
Here are my attempts below.
My domain class:
class JointMemberInvestment {
JointMember jointMember
int investAmount
Date investDate
static mapping = {
table('joint_member_investment')
version defaultValue: 0
}
static constraints = {
investAmount(nullable: false, blank: false)
investDate(nullable: false, blank: false)
}
}
My controller save method:
#Transactional
def save(JointMemberInvestment jointMemberInvestmentInstance) {
if (jointMemberInvestmentInstance == null) {
notFound()
return
}
String investDate = params.investDate;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse(investDate);
java.sql.Date sqlInvestDate = new java.sql.Date(date.getTime());
jointMemberInvestmentInstance.investDate = sqlInvestDate
jointMemberInvestmentInstance.jointMember = JointMember.get(Long.parseLong(params.jointMemberId))
if (jointMemberInvestmentInstance.hasErrors()) {
respond jointMemberInvestmentInstance.errors, view: 'create'
return
}
jointMemberInvestmentInstance.save flush: true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'jointMemberInvestment.label', default: 'JointMemberInvestment'), jointMemberInvestmentInstance.id])
redirect jointMemberInvestmentInstance
}
'*' { respond jointMemberInvestmentInstance, [status: CREATED] }
}
}
jointMemberInvestmentInstance.investDate = sqlInvestDate
jointMemberInvestmentInstance.jointMember = JointMember.get(Long.parseLong(params.jointMemberId))
bindData(jointMemberInvestmentInstance, params, [exclude:['JointMember']])
if (jointMemberInvestmentInstance.hasErrors()) {
respond jointMemberInvestmentInstance.errors, view: 'create'
return
}
May be this will help you.
Below is a generalized version of my Spring RestController implementation. It's purpose is to respond to HTTP requests at a specific base URI ("/rest/my/uri/to/resource") with a resource based on the URI ID input. It works fine, however due to the structure of the data it returns I have had to add an optional date param. I have the controller calculate today's date and use that in my database query when the user does not supply one in the URI.
My question to you is if I use the todaySqlDate variable for each response where the user does not supply a date as I am below, will it recalculate the date each time it responds to a request? Obviously if the user inputs a date like
/rest/my/uri/to/resource/identifier/666?date=2016-03-15
this will not be an issue. My concern is that when the date is not included, a la
/rest/my/uri/to/resource/identifier/666
it will use the default date. Will the default date stop being current if the service is left running for more than 24 hours?
#RestController
#RequestMapping(value = "/rest/my/uri/to/resource")
public class ResourceController
{
private static final Logger LOGGER = LoggerFactory.getLogger(ResourceController.class);
#Autowired
private ResourceService resourceService;
public String todaySqlDate = getTodaySqlDate();
#RequestMapping(value = "/identifier/{id}", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public Resource getResource(#PathVariable("id") String id,
#RequestParam(value="date", defaultValue="", required=false) String resourceDate)
throws InvalidParameterException, DataNotFoundException, Exception
{
LOGGER.trace("In ResourceController.getResouce() with {}", id);
try
{
if(!isValidIdentifier(id))
{
throw new InvalidParameterException("id is not valid: " + id);
}
if(resourceDate.isEmpty())
{
resourceDate = todaySqlDate;
}
else if(!isValidSqlDateString(resourceDate))
{
throw new InvalidParameterException("resourceDate is present but not valid: " + resourceDate);
}
ResourceList resourceList = resourceService.getResource(id, resourceDate);
if (resourceList == null)
{
LOGGER.trace("No resources found for given input");
throw new DataNotFoundException("ResourceList for " + id + " not found");
}
return resourceList;
}
catch (Exception e)
{
LOGGER.error(e.getMessage(), e);
throw e;
}
}
public String getTodaySqlDate()
{
java.util.Date utilDate = new java.util.Date();
java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());
return sqlDate.toString();
}
}
Yes, every new request will be handled by a new separate instance (thread) and hence it will re-calculate the date every time.
You can have a look at Spring/REST Documentation for more information.
Useful Link:
How are Threads allocated to handle Servlet request?
I am getting ClassCastException while getting the value from the Model.Please find the exception details below:
Caused by: java.lang.ClassCastException: java.util.Date cannot be cast to java.lang.String
at com.csscorp.presentation.spinneret.client.ams.AttendanceCaseCreationModel.getCheckinDate (AttendanceCaseCreationModel.java:164)
at com.csscorp.presentation.spinneret.client.ams.AttendanceCaseCreationGridEditor$8.handleEvent (AttendanceCaseCreationGridEditor.java:916)
Below is my code:
ColumnConfig checkinDatecolumn = new ColumnConfig();
checkinDatecolumn.setId("checkinDate");
checkinDatecolumn.setHeader("Check In Date");
checkinDatecolumn.setWidth(85);
checkinDatecolumn.setMenuDisabled(true);
checkinDatecolumn.setSortable(false);
final DateField dateField1 = new DateField();
dateField1.getPropertyEditor().setFormat(DateTimeFormat.getFormat("dd/MMM/yyyy"));
final String tempDate=dateField1.getRawValue();
dateField1.getDatePicker().addListener(Events.Select, new Listener<DatePickerEvent>() {
#Override
public void handleEvent(DatePickerEvent dpe) {
if(ACCCheckBoxModel.getSelectedItem().getRosterDate()!=null){
DateTimeFormat format = DateTimeFormat.getFormat("dd/MMM/yyyy");
rosterdate=format.parse(ACCCheckBoxModel.getSelectedItem().getRosterDate());
nextdate.setTime(rosterdate.getTime()+(1000*60*60*24));
prevdate.setTime(rosterdate.getTime()-(1000*60*60*24));
}
int rowIndex = caseStoreModule.indexOf(ACCCheckBoxModel.getSelectedItem());
Window.alert("Row Index-->"+rowIndex);
if(ACCCheckBoxModel.getSelectedItem().getCheckinDate().toString() == null){//here I am getting ClassCastException
if (rosterdate.compareTo(dateField1.getValue())==0 || nextdate.compareTo(dateField1.getValue())==0){
Window.alert("this is a valid date-->");
}
else {
Window.alert("Enter a valid date-->");
dateField1.reset();
}
}
else{
//Here I need to Implement validation logic if the value from the model is not null
}
}
});
In model class I am setting the checkinDate as String and DTO also I am setting it as String only. But Why ClassCastException is coming. I am not getting the cause for this.
Update
This is the line of AttendanceCaseCreationModel.java:164
163 public String getCheckinDate() {
164
return get("checkinDate");
165 }
Update
After calling toString method,ClassCastException is not coming.
return get("checkinDate").toString();
But When I check for null value,It's throwing the NullPointerException.
if(ACCCheckBoxModel.getSelectedItem().getCheckinDate() == null)
Exception details are below:
Caused by: java.lang.NullPointerException: null at com.csscorp.presentation.spinneret.client.ams.AttendanceCaseCreationModel.getCheckinDate(AttendanceCaseCreationModel.java:167) at com.csscorp.presentation.spinneret.client.ams.AttendanceCaseCreationGridEditor$8.handleEvent(AttendanceCaseCreationGridEditor.java:920)
Try the following:
public String getCheckinDate()
{
final Date date = (Date) get( "CheckinDate" );
return date == null ? null : date.toString();
}
Remove the toString() from getCheckinDate().toString().
I solved this.By below code change.
public String getCheckinDate() {
if(get("checkinDate")==null)
return null;
else
return get("checkinDate").toString();
}
Now it returns a String if it is not null.And null if it is null.