Java Play! 2 - password constraints - java

I can't find an #Equal constraint in Play! 2.
I looked through the API
http://www.playframework.org/documentation/api/2.0.2/java/index.html
I want to have a SignupForm that checks if the passwords are equal. I don't believe that I have to write my own constraint for such a common problem.
Something like:
...
#Min(6)
public String password;
#Equal(password)
public String confirmPassword;
...

I don't any #Equal contraint in other Java framework neither in the JSR 303.
To check for password, it's not difficult: in your form object, just write a public String validate() method:
public class SignupForm {
#Min(6)
public String password;
#Min(6)
public String confirmPassword;
public String validate() {
if(!password.equals(confirmPassword)) {
return "Password mismatch";
}
return null;
}
}
Take a look at the zentask sample, in this class.

In case anyone stumbles across this question from google. This is what I did
#MinLength(6)
public String password;
#MinLength(6)
public String confirmPassword;
public List<ValidationError> validate(){
List<ValidationError> errors = new ArrayList<ValidationError>();
if(!this.password.equals(this.confirmPassword)){
errors.add(new ValidationError("password", "Passwords must match."));
}
return errors.isEmpty() ? null : errors;
}
You have to use #MinLength(6) instead of #Min(6), I think that's because password is a string. Returning a List of validation errors will show up as an error in your form if someone doesn't enter a matching password. Otherwise, they won't see what is wrong.
I found useful information here https://www.playframework.com/documentation/2.2.x/JavaForms

The below code returns global error.
public String validate() {
if(!password.equals(confirmPassword)) {
return "Password mismatch";
}
return null;
}
But the snippet below more specifically returns error specific to confirmPassword field.
public List<ValidationError> validate(){
List<ValidationError> errors = new ArrayList<ValidationError>();
if(!this.password.equals(this.confirmPassword)){
errors.add(new ValidationError("confirmPassword", "Password should be same."));
}
return errors.isEmpty() ? null : errors;
}
Here is the official documentation that describes more on this.

Related

Validating input datatype

I am using below DTO class with respective annotations and are working fine also. But when I send a integer value for name/reqID(which is a String datatype) fields, still it is executing without any error/exception. How to avoid it or validate the datatype of incoming fields.
public class RequestDTO {
#NotEmpty(message = "Please provide reqID")
private String reqID;
#NotEmpty(message = "Please provide name")
private String name;
private Map <String, String> unknownProperties;
public AccountDTO(){
this.unknownProperties = new HashMap<String, String>();
}
public AccountDTO(String reqID, String name){
this.reqID= reqID;
this.name = name;
this.unknownProperties = new HashMap<String, String>();
}
#JsonAnySetter
public void add(String key, String value) {
this.unknownProperties.put(key, value);
}
#JsonAnyGetter
public Map <String, String> getUnknownProperties() {
return unknownProperties;
}
//getters and setters
}
working for { "reqID" : 56, "name" : 674 }. Have to check the datatype/reject the request. Any help would be appreciable.
If you're using Spring boot, by default it uses Jackson to parse JSON. There's no configuration option within Jackson to disable this feature
Here you will find interesting approaches to solving this problem:
Disable conversion of scalars to strings when deserializing with Jackson
You can disable MapperFeature ALLOW_COERCION_OF_SCALARS which is enabled by default.
Then conversions from JSON String are not allowed.
Doc Details here
public static final MapperFeature ALLOW_COERCION_OF_SCALARS
When feature is disabled, only strictly compatible input may be bound:
numbers for numbers, boolean values for booleans. When feature is
enabled, conversions from JSON String are allowed, as long as textual
value matches (for example, String "true" is allowed as equivalent of
JSON boolean token true; or String "1.0" for double).
Or create a custom json deserializer for string overriding default serializer JsonDeserializer<String>.
You could validate the input you are getting. But this is not specific to your DTO so if you have some sort of Utilities class with static methods (think about having one if you don't) it's better if you add it there and grab it for any DTO that might need this validation.
The validation method would look something like this:
public static boolean isNumber(String in) {
try{
Integer.parseInt(in);
// log something useful here
return true;
} catch(NumberFormatException e) {
return false;
}
}
You could then use this method throw your own exception. Then handle that the way you'd need:
if (Utilities.isNumber(reqID)){
throw new IllegalArgumentException("Meaningful Exception Message here");
}
I hope it helps! :)
Spring boot allows regular expression checking using #Patter annotation. So just add the following
#Pattern(regexp="[a-zA-Z]")
#NotEmpty(message = "Please provide name")
private String name;

Method returning alternative data structures based on execution result

Say I have a function that looks at a file and returns two results: recognized and unrecognized. When it returns the recognized result, I want the result to also contain a message but when it is unrecognized, no message is necessary.
public Result checkFile(File file) {
...
}
There are two ways I can think of to accomplish this...
Have the Result class like so:
class Result {
private Type type;
private String message;
enum Type {
RECOGNIZED, UNRECOGNIZED
}
}
Or do it like so:
class Result {
}
class Unrecognized extends Result {
}
class Recognized extends Result {
private String message;
}
I'm inclined to use the second method, even though I'd have to check the result using instanceof and I've read that instanceof should be avoided whenever possible, but doing this avoids having a null message when the result is unrecognized. For this example a null message wouldn't be much of an issue, but what if there is a lot more data associated with a recognized result? It seems like worse practice to me to instantiate a class that could have all null fields.
What is the best practice to handle this situation? Is there some standard method or pattern?
Two classes might be overkill, because of it being one and the same class of object. Also an enum with two values which merely reassemble true and false is not required. One class Result should suffice and this would also remove the demand for a common interface. I'd be all for "no complexity beyond necessary" ...
class RecognitionResult {
private String message = "default message";
private boolean recognized = false;
public Result() {}
public Result(boolean value) {
this.setRecognised(value);
}
public boolean setRecognised(boolean value) {
this.recognized = value;
}
public boolean setMessage(#NonNull String value) {
this.message = value;
}
public boolean getRecognised() {
return this.recognized;
}
#Nullable
public String getMessage() {
return this.recognized ? this.message : null;
}
}
then one can simply do:
return new RecognitionResult(true);
an interface for asynchronous callbacks might look alike this:
interface Recognition {
void OnComplete(RecognitionResult result);
}
or if you really want to optimize:
interface Recognition {
void OnSuccess(RecognitionResult result);
void OnFailure(RecognitionException e);
}
Of course there's no 'correct' design here - it's going to be a matter of opinion which way you go. However my view is that the modern trend in OOD is to minimise the use of extension and to use delegation and implementation of interfaces wherever possible.
As a general rule, whenever you think of using instanceof, reconsider your design.
This would be my suggestion:
interface Result {
boolean isRecognised();
String getMessage();
}
class RecognisedResult implements Result {
private final String message;
public boolean isRecognised() {
return true;
}
public String getMessage() {
return message;
}
}
class UnrecognisedResult implements Result {
public boolean isRecognised() {
return false;
}
public String getMessage() {
throw new UnsupportedOperationException("No message for unrecognised results");
}
}
you can look at the way Retrofit implement your concept of "recognised" and "message"
https://square.github.io/retrofit/2.x/retrofit/retrofit2/Response.html. it is similar to your first method.
what they did is to have a class called Response, containing a method called isSuccessful(), and a method called body() containing the payload if it's successful (or null if it is unsuccessful.
you can try some thing like the following
class Result {
private Type type;
private String message;
public bool isSuccessful(){
return type == RECOGNIZED;
}
public String getMessage(){
return message; //null if unrecognized.
}
enum Type {
RECOGNIZED, UNRECOGNIZED
}
}
The functional way to do this would be to use an Either type, which doesn’t come with the JDK, but is available in vavr library. Based on your comments on this thread, it appears you don’t clearly understand how type inheritance works. In that case, a functional solution may be overkill, and I’d suggest going with #sprinter’s solution.

Spring Rest Json Mapping on POST (Invalid Property)

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.

bindFromRequest validation null

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()

Play framework sometimes needs getters and setters, sometimes it does not

I started a simple webapp based on play. After a bit of refactoring the login-form stopped working. I used an entity-bean with simple public fields. I moved it from one controller to another while refactoring and of cause corrected the references. It always told me I'm an invalid user.
During debugging I've found that the fields aren't set anymore. However, what really confused me: I manually added getters and setters to the public fields and suddenly it worked again. I've done now quite a bit of research why it works in the default-controller called "Application" but not in my own one called "Registration".
There isn't much code involved, here a few points:
public class RegistrationLogin extends Controller {
public static class Login {
#Required
public String email;
#Required
public String password;
public String validate() {
/* here is the interesting part, when I call "form.hasErrors" in
authenticateLogin and this validate-method gets called, email and
password both are null. If I create getters and setters they are set correctly */
if (User.authenticate(email, password) == null) {
return "Invalid user or password";
}
return null;
}
}
public static Result authenticateLogin() {
Form<Login> loginForm = form(Login.class).bindFromRequest("email", "password");
String title = "Login";
if (loginForm.hasErrors()) {
return badRequest(login.render(title,loginForm));
} else {
session().clear();
session("email", loginForm.get().email);
return redirect(
routes.Application.show(Ebean.find(User.class).where().ieq("email",loginForm.get().email).findUnique().getName())
);
}
}
When I had Login defined in Application (the default-controller which is generated when you start a project) it worked with just the fields.
Whats the origin of this behavior? Any hint might be helpful.

Categories