I have my validate method in my TestValidator as follows
#Override
public void validate(Object target, Errors errors) {
Test test = (Test) target;
String testTitle = test.getTestTitle();
//**ErrorCheck1** - This works, and I am able to pull the value in my controller
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "testTitle", "test.testTitle.projec", "My msg");
if (testTitle != null && testTitle.length() < 4) {
logger.error("Inside custom validation"+test.testTitle().length());
//**Error Check2**
//***HOW DO I RETRIEVE THE BELOW VALUE in My controller
errors.rejectValue(testTitle, "test.testTitle.lessThen4");
errors.addAllErrors(errors);
logger.error("Entered If condition of validate");
}
}
And my controller is
#RequestMapping(value = "/test", method = RequestMethod.PUT)
public ResponseEntity<BasicResponseDTO> newTest(#Valid #RequestBody Test test, BindingResult result) {
if (result.hasErrors()){
logger.error("Entered Errors");
BasicResponseDTO basicResponseDTO = new BasicResponseDTO();
basicResponseDTO.setCode(ResponseCode.BAD_REQUEST);
return new ResponseEntity<BasicResponseDTO>(basicResponseDTO, HttpStatus.BAD_REQUEST);
}
}
When my ErrorCheck1 condition is activated, my IF condition inside the controller is able to retrieve it.
However, in my ErrorCheck2, because of of the errors.rejectValue I immediately get an error on the console and am not able to gracefully handle the situation when the testTitle length is less than 4.
What is the alternative to errors.rejectValue so that I may handle the
error in my controller ?
Ok - Got it. All i had to do was change
errors.rejectValue(testTitle, "test.testTitle.lessThen4");
to
errors.reject(testTitle, "test.testTitle.lessThen4");
RejectValue is a Field error and is not global in nature.
Reject is a Global error and can be accessed from inside the errors list in the controller.
From the Documentation
void reject(String errorCode, String defaultMessage);
Register a global error for the entire target object, using the given error description.
#Override
public void validate(Object target, Errors errors) {
Test test = (Test) target;
String testTitle = test.getTestTitle();
//**ErrorCheck1** - This works, and I am able to pull the value in my controller
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "testTitle", "test.testTitle.projec", "My msg");
if (testTitle != null && testTitle.length() < 4) {
logger.error("Inside custom validation"+test.testTitle().length());
//**Error Check2**
//***HOW DO I RETRIEVE THE BELOW VALUE in My controller
errors.reject(testTitle, "test.testTitle.lessThen4");
errors.addAllErrors(errors);
logger.error("Entered If condition of validate");
}
}
Hope that helps someone.
You cannot access the value directly but there is a way to include the value into error message
${validatedValue}
If you annotate a field like this
#Size(min = 10, message =”Phone number entered [${validatedValue}] is invalid. It must have at least {min} digits”)
private String phoneNumber;
and enter 123 your error message should be
Phone number entered [123] is invalid. It must have at least 10 digits. Thus you can access the value.
See https://raymondhlee.wordpress.com/2014/07/26/including-field-value-in-validation-message-using-spring-validation-framework-for-jsr-303/
Related
This is a weird one for me. I've done the entities and the controllers and the form validation before, but I'm confused on this error.
So backstory. This is spring-boot w/Hibernate, connecting to a PostgreSQL Db. What I am attempting to do, is map a POST request to creating a resource. I'm trying to do this with pure JSON. I've been able to achieve this before.
The error in question is...
Invalid property 'Test' of bean class [com.example.api.entities.forms.OrganizationRegistrationForm]: Bean property 'Test' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
The request body, as it is in Postman is...
{
"organizationName":"Test",
"employees":10
}
The OrganizationRegistrationForm class it's complaining about...
public class OrganizationRegistrationForm {
#NotEmpty
private String organizationName = "";
#NotNull
private int employees;
private JsonNode contactInfo;
private JsonNode locationInfo;
public String getOrganizationName() {
return organizationName;
}
public void setOrganizationName(String name) {
this.organizationName = name;
}
public int getEmployees() {
return employees;
}
public void setEmployees(int employees) {
this.employees = employees;
}
public JsonNode getContactInfo() {
return contactInfo;
}
public void setContactInfo(JsonNode contactInfo) {
this.contactInfo = contactInfo;
}
public JsonNode getLocationInfo() {
return locationInfo;
}
public void setLocationInfo(JsonNode locationInfo) {
this.locationInfo = locationInfo;
}
}
And in case you need it, the request method...
#RequestMapping(value="/organization", method = RequestMethod.POST)
public Organization registerOrganization(#Valid #RequestBody OrganizationRegistrationForm form,
BindingResult bindingResult) throws Exception {
if(bindingResult.hasErrors()) {
LOGGER.error("The registration form entered has errors: {}", bindingResult.getAllErrors().toString());
throw new InvalidForm();
}
try {
Organization org = orgService.registerOrganization(form);
if(org!=null)
return org;
} catch(DataIntegrityViolationException e) {
bindingResult.reject("name.exists", "The supplied name is already in use");
}
throw new InvalidForm();
}
Although I'm guessing it doesn't even get that far. Originally the orginazationName field was called "name", but I changed it to see if maybe that was the issue.
The even weirder part for me is when I used this JSON object it worked. But created an organization named "organizationName".
{
"organizationName":"organizationName",
"employees":10
}
And one time it even complained that the invalid property was ''. As in empty. What am I doing wrong here?
I don't know how, or why. But for some reason the answer seemed to be in the OrganizationRegistrationFormValidator class that the binder uses.
The evil line in question was in validate(Object target, Errors errors) method...
ValidationUtils.rejectIfEmptyOrWhitespace(errors, target.getOrganizationName(), "name.empty", "Please enter a name");
Changing that line to a classic check worked.
if(target.getOrganizationName.isEmpty())
errors.reject("name.empty", "Please enter a name");
For documentation sake, anyone know why that happened? Are my api docs wrong when IntelliSense suggested that method signature?
I know this is old but I just stumbled over it:
to me ValidationUtils.rejectIfEmptyOrWhitespace(errors, target.getOrganizationName(), "name.empty", "Please enter a name"); looks wrong.
It should be:
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "organizationName", "name.empty", "Please enter a name");
The second attribute is the Field Name, not its content. ValidationUtils will take that name and transform it to the standard getter (getOrganizationName in that case) to retrieve its value and validate that.
This is why it tells you ther is no property named Test. Because there is none.
I have an HTML form that is submitting data to a spring post method. I've enabled validation with the javax.validation library and the #Valid tag:
public String openForm(#ModelAttribute("task")#Valid Task task,
BindingResult result, Model model) {
if(result.hasErrors()) {
System.out.println("Form does not validate.");
List<ObjectError> errors = result.getAllErrors();
for(ObjectError error: errors) {
System.out.println(error.getDefaultMessage());
}
}
return "home";
}
Task is the main object being binded to the form, but Task contains a class called User. User has a fullName. There are two fields that I am trying to validate:
systemType is a String within the Task object:
#Size(min=1, message="The System Type must contain a valid option")
private String systemType;
fullName is a String within the User object:
#Size(min=1, message="A User must be selected.")
private String fullName;
The validation itself is working, but what I am trying to figure out how to do is get the default message working. When I iterate through the BindingResult result for errors and print out the error.getDefaultMessage() the systemType error message works as expected.
However, when there is a validation error with the fullName field, it prints:
Property 'user.fullName' threw exception; nested exception is java.lang.ArrayIndexOutOfBoundsException: 1
I believe this to be because it is an inner class of the main class Task which is what is actually being validated. I guess I could just write some logic to say that if this error comes along to just print the error message I actually want - but is there a way to go within error and get the default message I originally specified?
I'm trying to run 2 tests with MockMVC (Spring framework).
The first one add a user. When the user is added, an userID is generated, and returned.
The second should delete the added user from this userID.
At the start of my test class, I have this variable: String userID;
Here is the test where I create the user (it works). After creating the user, I get from the response the generated ID for this user.
#Test
public void it_adds_a_new_user() throws Exception {
MvcResult result = mockMvc
.perform(post("/users")
.contentType(MediaType.APPLICATION_JSON)
.content("User infos, in JSON..."))
.andExpect(status().isOk())
.andReturn();
//Next lines just take the ID from the response
Matcher matcher = Pattern.compile("\\d+").matcher(result.getResponse().getContentAsString());
matcher.find();
this.userID = matcher.group();
System.out.println(userID); //Correctly print the generated ID
}
Now, I try to delete this poor guy:
#Test
public void it_deletes_the_new_user() throws Exception {
System.out.println(userID); //It prints null!
mockMvc.perform(delete("/users/" + userID)
.contentType(MediaType.APPLICATION_JSON)
.andExpect(status().isOk()); //400 because userID is null :-(
}
The problem is that userID is correctly initialized in the first test, but is null in the second (it is a class variable). I don't understand why.
Can you help me running those tests, and if possible explain me why userID == null on my second test ?
Thanks!
create getter and setter method for set and get the value userID like:
void setUserId(matcher.group())---->should be inside it_adds_a_new_user()
now you have setted the userId
add one gette method also,
get the value by calling getUserId()----->should be inside it_deletes_the_new_user()
since i dont know the structuer of your program so giving you just an idea to solve you problem.
I am new to the Java Play Framework and I'm trying to get the authentication to work. So I am following this tutorial: https://www.playframework.com/documentation/2.1.0/JavaGuide4
Here is my code:
public static Result authenticate()
{
Form<Login> loginForm = form(Login.class).bindFromRequest();
return ok(loginForm.toString());
}
public static class Login
{
public String email;
public String password;
public String validate()
{
return "VALIDATE "+email+password;
}
}
In the method autheticate() I can see the submitted values of the form, but the method validate() in the Login class does not see them (the variables are always null).. The output of loginForm.toString() contains:
Form(of=class controllers.Application$Login, data={email=asdf#asdf, password=asdf}, value=None, errors={=[ValidationError(,[VALIDATE nullnull],[])]})
As you can see, the data is received.. But in the validate method the data suddenly is equal to null. So how do I fix this?
You don't mention how you are calling validate() however I think this might do the trick, do something along the lines of:
public static Result authenticate() {
Form<Login> form = form(Login.class).bindFromRequest();
// handle errors
if (!form.hasErrors()) {
Login login = form.get();
Logger.debug(login.validate());
} else {
// bad request
}
}
This works for me.
Method validate in your model should return null if you think that validation has passed, otherwise you should return error message text. Then you need to check form if it contains error by "hasGlobalError" method. globalError is filled when validate() method returns String instead of null. But in your case you should use some model field annotations - https://www.playframework.com/documentation/2.3.x/api/java/play/data/validation/Constraints.html.
If you want to check if form fails on those - then you use "hasErrors" method.
public static class Login {
#Constraints.Email
public String email;
#Constraints.MinLength(value = 6)
public String password;
}
Such model will check if provided emails is really email and if password is longer or equal 6 characters.
ps. Do not use toString on template, you should use render()
I am attempting to create a registration handler for my Play Framework application but I am running into some trouble. The goal of this code is to grab the data that was submitted and then check if the username or email is in use. This is done using methods built into my User class, which is a model.
The register method:
public static F.Promise<Result> register() {
// Get the POST data and turn it into something we can read from
DynamicForm form = Form.form().bindFromRequest();
// Get the email, username, and password
String email = form.get("email");
String username = form.get("username");
String password = form.get("password");
return User.findByUsername(username).map(user -> {
// For .map to run we must not have encountered an error, this means
// a user already has this username (otherwise the doc would not exist)
return redirect("/register");
}).recover(userCheckError -> {
// For .recover to run there must have been an error. This will happen
// if a doc was not found with the username (therefore it is not in use)
return User.findByEmail(email).map(option -> { // ERROR START
// We now have an F.Option object. If the email is already taken,
// then the Option is defined (has a value within it), if the email
// is free, the Option will be undefined (no value within it)
if (option.isDefined()) {
return redirect("/register");
} else {
return redirect("/register");
}
}); // ERROR END
});
}
The findByUsername and findByEmail methods (in the User class):
public static F.Promise<User> findByUsername(String username) {
return bucket.get(username.toLowerCase(), User.class);
}
public static F.Promise<F.Option<User>> findByEmail(String email) {
return bucket.find("users", "by_email", QueryHelper.findOne(email), User.class).map(result ->{
if (result.isEmpty()) {
return F.Option.None();
} else {
User user = result.iterator().next();
return F.Option.Some(user);
}
});
}
Edit: I have added comments to the register method and removed some unneeded code. I have also labeled where the error starts and ends (the lines that IntelliJ is highlighting. The exact error is "bad return type in lambda expression". The register method needs to return a Promise<Result> but that block of code is returning a Promise<B> (generic?).
Javadocs:
http://www.playframework.com/documentation/2.3.x/api/java/play/libs/F.Promise.html
http://www.playframework.com/documentation/2.3.x/api/java/play/libs/F.Option.html