#Valid for long data type is not working for mandatory check - spring-boot

I have the below input class and when i trigger the api without 'interactionId' param in the input,
I expect validation error message "interactionId cannot be empty" but the validation passes through which i guess could be due to the fact that interactionId has a default value of 0.
Can someone pls. help to enforce this validation on the 'long' parameter when its not given in input?
with #NotEmpty for the customerId param, its working as expected. Using #NotEmpty for the long param "interactionId" is throwing a different error that #notempty cannot be used for long.
public class Input {
#NotEmpty(message = "customerId cannot be empty")
private String customerId;
#Valid
#NotNull(message = "interactionId cannot be empty")
private long interactionId;
// setters and getters
}
my controller class:
#RestController
public class Controller {
#PostMapping(value="/detailed-customer-transaction", produces =
MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<Object> detailTransactions(#Valid #RequestBody Input
params)
{
return new ResponseEntity<>(Dao.detailTransactions(params), HttpStatus.OK);
}
Above issues is resolved after changing to Long instead of long.
Query #2
I need another help. I have a String input param which takes date-time format in below format. Given its a string parameter, how can i validate for the pattern="yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"

long should be Long, because long is a primary type in java, not an object, so Long is an object that can be checked whether it is null

Related

RequestBody and camel case request parameters

I have an endpoint with a request body:
#PostMapping("/v1/message")
#PreAuthorize("#oauth2.isAnyClientId(#authorizeConfig.getIds())")
public void receive(
#RequestBody #NotNull #Valid final Message message,
#RequestHeader final HttpHeaders headers) {
...
}
The Message class has several parameters:
#Builder
#Getter
#Setter
#EqualsAndHashCode
#NoArgsConstructor
#AllArgsConstructor
#JsonPropertyOrder(alphabetic = true)
public class Message {
#NotBlank(message = "tenant is empty")
private String tenant;
#NotBlank(message = "messageId is empty")
private String messageId;
#NotBlank(message = "payload is empty")
private String payload;
#NotNull(message = "messageType is empty")
private MessageType messageType;
private String xSchemaVersion;
}
When I perform a request to that endpoint:
{
"tenant":"client1",
"messageId":"670f13e15d554b2bba56f6d76d33b79c",
"payload":"",
"messageType":"MessageType.Email",
"xSchemaVersion":"2.7.3"
}
I get the following error:
{
"status": 400,
"date": "2022-07-18T08:21:21.430+0000",
"exception": "missing parameter: xSchemaVersion",
"description": "uri=/v1/message"
}
But if I do the following instead:
{
"tenant":"client1",
"messageId":"670f13e15d554b2bba56f6d76d33b79c",
"payload":"",
"messageType":"MessageType.Email",
"xschemaVersion":"2.7.3"
}
I get 200 OK.
Notice that the only thing I changed is the lowercase s in xschemaVersion instead of xSchemaVersion.
Why is this necessary?
This is happening because you are using lomboks getter & setter for your Message entity.
If you check, lombok will generate get & set for your xSchemaVersion as
getXSchemaVersion() & setXSchemaVersion(..), which is quite different than what any IDE would automatically generate for us.
If I use eclipse for generating getters & setters for xSchemaVersion it would be getxSchemaVersion() & setxSchemaVersion(..); and this is what spring is also looking for as valid getter & setter for field xSchemaVersion (based on reflaction).
Because lombok is making your x & s as an upper case, spring is unable to map your xSchemaVersion with input if you use xSchemaVersion.
The reason it works with xschemaVersion because, spring is able to map field as it does lowecase conversion for words after get & set( getXSchemaVersion() & setXSchemaVersion(..).)
Workaround -- create separate getter & setter in your Message for xSchemaVersion as getxSchemaVersion & setxSchemaVersion(..) which acts as overriding methods of default generated getter /setter of lombok.
Once you do this, you can successfully able to use xSchemaVersoin in your input.
According to Project Lombok https://projectlombok.org/features/GetterSetter
you can add AccessLevel.PRIVATE to the GETTER SETTER for not used field.
#Getter(AccessLevel.PRIVATE) #Setter(AccessLevel.PRIVATE) String xSchemaVersion;

Creating custom requestParam in springboot controller

i have a use case where the user can send following params with get request
GET localhost/8080/users?filter=alex
OR
GET localhost/8080/users?suffixFilter=lex
OR
GET localhost/8080/users?prefixFilter=a
is it possible to add only one request param instead of 3 in controller
e.g.
instead of
#GetMapping("/users")
#ResponseBody
public String getFoos(#RequestParam String filter, #RequestParam String prefixFilter , #RequestParam String suffixFilter) {
return "ID: " + id;
}
is it possible to create a dynamic one which includes those three variantes? I was thinking creating class like this
public class FilterCreteria {
private String filter;
private String suffixFilter;
private String prefixFilter;
}
and then passing this to controller
#GetMapping("/users")
#ResponseBody
public String getFoos(#RequestParam FilterCreateria filter) {
return "ID: " + id;
}
the problem is if i send filter=alex the other attributes in the class FilterCreteria is null and i want to avoid this null.
What i searching for:
is there other way of making this possible?
if my suggestion is ok, how to avoid null attributes when the user only sends one queryparam like filter=alex?

Spring boot rest requestbody and #valid not working when object is null/empty

I am trying to apply not null validation on an attribute of my request which is instructedAmount but it is not working. I have a Spring Boot (V2.3.0.RELEASE) application with the following endpoints:
#Validated
public class TestController {
#PostMapping(value = "/test/pay")
public ResponseEntity<IPSPaymentResponse> validatePayt(#Valid #RequestBody InstantPaymentRequest instantPaymentRequest) {
log.debug("start validatePayment method {}", instantPaymentRequest);
....
The InstantPaymentRequest is as follows:
#Data
#Validated
public class InstantPaymentRequest {
#Valid
private PaymentIdentificationRequest paymentIdentification;
#NotBlank(message = "transactionTypeCode.required")
private String transactionTypeCode;
#Valid
private InstructedAmount instructedAmount;
#Valid
private CustomerRequest debtor;
The instructed amount is as follows:
#Data
public class InstructedAmount {
#NotBlank(message = "currency.required")
private String currency;
#NotBlank(message = "value.required")
private String value;
}
Basically when the instructedAmount is provided in the payload but for example I miss currency attribute in payload, the validation is working fine, the non null error message is displayed correctly and my rest controller endpoint is not called.
However when instructedAmount is not provided in the payload, no mandatory error message is displayed and my rest endpoint is called, it this the correct way or I am missing something?
I thought since attribute of InstructedAmount cannot be null then InstructedAmount also cannot be null/empty.
How to add InstructedAmount not null validation in the above scenario with annotation?
Use #NotNull together with #Valid:
#NotNull
#Valid
private InstructedAmount instructedAmount;
From https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#section-object-graph-validation:
Note that null values are getting ignored during cascaded validation.

Marking a field as mandatory in the request body for a specific request

I intend to use the same bean as request body for creating/updating/deleting profile (depending on request methods). There are two scenarios for an update. First is updating profile where any parameter like firstName, lastName etc. can be updated except the emailAddress and the second is updating only the emailAddress. For the first case newEmailAddress is optional but for the second case, newEmailAddress field is mandatory.
Below is a sample bean:
class ProfileModel {
#NotEmpty
#Email
private String emailAddress;
#Size(max=30)
private String firstName;
#Email
private String newEmailAddress;
.
.
.
}
I created different API endpoints for updating profile and updating the email address. I tried to find a way to make newEmailAddress field as optional for the first request and required for the second request but couldn't find anything but to manually check in the controller method for the second request and throw Exception.
Is there any other way through which this can be achieved?
The validation groups should solve your problem. See the examples either on beanvalidation.org or at hibernate-validator documentation page.
Basically you will need to add a group attribute value to your annotation constraints. Something like:
class ProfileModel {
#NotEmpty
#Email
private String emailAddress;
#Size(max=30)
private String firstName;
#Email(groups= UpdateEmail.class)
private String newEmailAddress;
and then on your controllers make use of Springs #Validated annotation which allows you to pass a group for which you want to validate.
One endpoint could use then this UpdateEmail group and the other the Default one.
This can be achieved using validation groups. That needs an identifier class or interface.
So you can do something like this:
=> Define a validation group identifier. It can be a class or interface.
public interface MyValidationGroup{}
=> Specify the validation group on request body.
class ProfileModel {
#NotEmpty
#Email
private String emailAddress;
#Size(max=30)
private String firstName;
#Email
#NotBlank(groups={MyValidationGroup.class})
private String newEmailAddress;
.
.
.
}
=> Specify validation group on controller method.
public ProfileModel add(#Validated({MyValidationGroup.class})
#RequestBody ProfileModel profile){
...
}

How to validate till the first violation using hibernate validator

I am new to using hibernate validator. I just want to know if there is a way to stop further validations when I get the first violation.
For example consider my case below.
public class CustomerDetails {
#NotNull
#Size(min=10, max=10)
private String CustomerID;
#NotNull
private String customerName;
#NotNull
#Pattern([0-9]*)
private String phoneNumber;
}
What I want to accomplish, is to make the validator to stop validating the other fields if the first field "CustomerID" itself is invalid. If the customerID is valid, we proceed to validate the next field customerName. In case that is not valid, the validator must stop there and not validate further. What I am concerned about is the performance. If my bean under test has 100 fields, will it not impact performance to validate all the 100 if the first one itself is not valid and I can display only one error to my end user?

Resources