I have a "Validator" class which allows us to set values of its member variables (mostly boolean) - mv1, mv2, mv3 etc. with setter methods. Lets call all these variables "settings". All the setter methods return this Validator instead of the usual void. A Validator is setup and then used by automation test methods to validate the json/string response body of an api call made in the test method.
The Validator has a validate(Input input) method which takes an "Input" object (actually an api response) and validates it based on the values of settings of Validator. There are some dependencies between the various settings. For example, if mv1 = true, then mv3 cannot be true etc. Also, I cannot always use enums to restrict the values of the settings !
I validate all the settings with validateSettings(). The validate(Input input) calls it before doing the validation. I want to find out all the invalid inputs, display them all at once and then prevent the validation until the inputs are fixed. What is the best way to do this in Java ?
What did I try ?
Using plain Java -
I used a string to store all the invalid settings and with reasons why they are invalid. Then, throw an IllegalArgumentException if one or more settings were found to be invalid and pass it the string. I want to avoid writing custom code if possible. I also don't want to use Java's assert because it can be disabled at run time.
Using TestNg library-
I use a SoftAssert to validate the member variables. The code inspects some of the the member variables, asserts that the variables have valid values and finally does softAssert.assertAll() to list all the wrong values at once. But, I wonder if Java has any in-built features to do this.
class Validator {
// Validator settings
boolean mv1;
boolean mv2;
boolean mv3;
boolean mv4;
boolean mv5;
//MyEnum mv6;//...etc.
// Setters - One example.
public Validator setMv1(boolean mv1) {
this.mv1 = mv1;
return this;
}
// Validation logic
public void validate(Input input) {
validateSettings();
// Now, validate the input.
}
// Validate the settings of this Validator - using TestNg library
private void validateSettings() {
SoftAssert assertz = new SoftAssert();
// No need to validate all settings ! Only some needed.
if (mv1 == true) {
assertz.assertFalse(mv3, "Meaningful error message");
assertz.assertTrue(mv5, "Meaningful error message");
}
// Assert other things.
assertz.assertAll();
}
// Validate the settings of this Validator - using plain Java.
private void validateSettingsV1() {
String errors = "These are the invalid settings - ";
boolean areSettingsInvalid = false;
if (mv1 == true) {
if (mv3 == true) {
errors += "mv3 can't be true when...blah";
areSettingsInvalid = true;
}
if (mv5 == false) {
errors += "mv5 can't be false when...blah";
areSettingsInvalid = true;
}
// Repeat above logic for all invalid settings.
if (areSettingsInvalid == true) {
throw new IllegalArgumentException(errors);
}
}
}
}
Related
I am currently using HibernateConstraintValidator to implement my validations. But my reviewer is not fine with having if/else in code or ! operators. Which design pattern can I use to remove the if/else in my validation logic?
public class SomeValidatorX implements ConstraintValidator<SomeAnnotation, UUID> {
#Autowired
SomeRepository someRepository;
#Override
public boolean isValid(UUID uuid, ConstraintValidationContext context) {
return !(uuid!=null && someRepository.existsById(uuid)); //The reviewer doesn't want this negation operator
}
}
And in below code, he doesn't want if/else
public class SomeValidatorY implements ConstraintValidator<SomeAnnotation, SomeClass> {
#Autowired
SomeRepository someRepository;
#Override
public boolean isValid(SomeClass someObject, ConstraintValidationContext context) {
if(someObject.getFieldA() != null) { //He doesn't want this if statement
//do some operations
List<Something> someList = someRepository.findByAAndB(someObject.getFieldA(),B);
return !someList.isEmpty(); //He doesn't want this ! operator
}
return false; // He was not fine with else statement in here as well
}
}
Side Note: We have to use Domain Driven Design (if it helps)
A long time ago, in the beginning of time. There was a guideline that said that methods should only have one exit point. To achieve that, developers had to track the local state and use if/else to be able to reach the end of the method.
Today we know better. By exiting a method as early as possible it's much easier to keep the entire flow in our head while reading the code. Easier code means less mistakes. Less mistakes equals less bugs.
In my opinion, that's why the reviewer doesn't like the code. It's not as easy to read as it could be.
Let's take the first example:
public boolean isValid(UUID uuid, ConstraintValidationContext context) {
return !(uuid!=null && someRepository.existsById(uuid)); //The reviewer doesn't want this negation operator
}
What the code says is "not this: (uuid should not be empty and it must exist)". Is that easy to understand? I think not.
The alternative: "Its OK if uuid do not exist, but if it do, the item may not exist".
Or in code:
if (uuid == null) return true;
return !someRepository.existsById(uuid);
Much easier to read, right? (I hope that I got the intention correct ;))
Second example
if(someObject.getFieldA() != null) { //He doesn't want this if statement
//do some operations
List<Something> someList = someRepository.findByAAndB(someObject.getFieldA(),B);
return !someList.isEmpty(); //He doesn't want this ! operator
}
return false; // He was not fine with else statement in here as well
Ok. Here you are saying:
If field A is not null:
Build a list where A and b is found
If that list is not empty fail, otherwise succeed.
Otherwise fail
A easier way to conclude that is to simply say:
It's ok if field A is not specified
If field A is specified it must exist in combination with B.
Translated to code:
if (someObject.getFieldA() == null)
return true;
return !someRepository.findByAAndB(someObject.getFieldA(),B).isEmpty();
In C# we have Any() which is opposite to isEmpty which I would prefer in this case as it removes the negation.
Sometimes negations are required. It doesn't make sense to write a new method in the repository to avoid it. However, if findByAAndB is only used by this I would rename it to ensureCombination(a,b) so that it can return true for the valid case.
Try to write code as you talk, it makes it much easier to create a mental picture of the code then. You aren't saying "Im not full, lets go to lunch", are you? ;)
You can check the Null-object pattern.
The general pattern is to ban null completely from your code. This eliminates the ugly null checks. In this point I agree with your code reviewer.
Following the below recommendations will result in:
public boolean isValid(SomeClass someObject, ConstraintValidationContext context) {
return someRepository.containsAAndB(someObject.getFieldA(), B);
}
Avoid null checks
Before introducing the Null-object pattern, simply apply the pattern or convention to enforce initialization of all references. This way you can be sure that there are no null references in your entire code.
So when you encounter a NullPointerException, you don't solve the issue by introducing a null check, but by initializing the reference (on construction) e.g., by using default values, empty collections or null objects.
Most modern languages support code analysis via annotations like #NonNull that checks references like arguments and will throw an exception, when a parameter is null/not initialized. javax.annotation for instance provides such annotations.
public void operation(#NonNull Object param) {
param.toString(); // Guaranteed to be not null
}
Using such annotations can guard library code against null arguments.
Null-Object Pattern
Instead of having null references, you initialize each reference with a meaningful value or a dedicated null-object:
Define the Null-object contract (not required):
interface NullObject {
public boolean getIsNull();
}
Define a base type:
abstract class Account {
private double value;
private List<Owner> owners;
// Getters/setters
}
Define the Null-object:
class NullAccount extends Account implements NullObject {
// Initialize ALL attributes with meaningful and *neutral* values
public NullAccount() {
setValue(0); //
setOwners(new ArrayList<Owner>())
#Override
public boolean getIsNull() {
return true;
}
}
Define the default implementation:
class AccountImpl extends Account implements NullObject {
#Override
public boolean getIsNull() {
return true;
}
}
Initialize all Account references using the NullAccount class:
class Employee {
private Account Account;
public Employee() {
setAccount(new NullAccount());
}
}
Or use the NullAccount to return a failed state instance (or default) instead of returning null:
public Account findAccountOf(Owner owner) {
if (notFound) {
return new NullAccount();
}
}
public void testNullAccount() {
Account result = findAccountOf(null); // Returns a NullAccount
// The Null-object is neutral. We can use it without null checking.
// result.getOwners() always returns
// an empty collection (NullAccount) => no iteration => neutral behavior
for (Owner owner : result.getOwners()) {
double total += result.getvalue(); // No side effect.
}
}
Try-Do Pattern
Another pattern you can use is the Try-Do pattern. Instead of testing the result of an operation you simply test the operation itself. The operation is responsible to return whether the operation was successful or not.
When searching a text for a string, it might be more convenient to return a boolean whether the result was found instead of returning an empty string or even worse null:
public boolean tryFindInText(String source, String searchKey, SearchResult result) {
int matchIndex = source.indexOf(searchKey);
result.setMatchIndex(matchIndex);
return matchIndex > 0;
}
public void useTryDo() {
SearchResult result = new Searchresult();
if (tryFindInText("Example text", "ample", result) {
int index = result.getMatchIndex();
}
}
In your special case, you can replace the findByAAndB() with an containsAAndB() : boolean implementation.
Combining the patterns
The final solution implements the Null-Object pattern and refactors the find method. The result of the original findByAAndB() was discarded before, since you wanted to test the existence of A and B. A alternative method public boolean contains() will improve your code.
The refactored implementation looks as followed:
abstract class FieldA {
}
class NullFieldA {
}
class FieldAImpl {
}
class SomeClass {
public SomeClass() {
setFieldA(new NullFieldA());
}
}
The improved validation:
public boolean isValid(SomeClass someObject, ConstraintValidationContext context) {
return someRepository.containsAAndB(someObject.getFieldA(), B);
}
You can try this
return Optional.ofNullable(uuid)
.map(someRepository::existsById)
.orElse(false);
StudentDTO class having around 20 string attributes and each need to validate whether mandatory or not based on the logic given below in comments. This will make update method lengthy with too many if else's. Exception message should change based on the property evaluating. This code use Java 11.
// all fields except lastUpdated are string
public Student populateStudent(final StudentDTO studentDTO) {
Student student = new Student();
boolean dataUpdated = false;
/*
If mandatory parameter is:
1.) null : parameter is not updating
2.) empty : validate and throw an exception
3.) blank : validate and throw an exception
*/
if (isEmptyOrBlank(studentDTO.getName())) {
handleBadParam("Bad student name");
} else {
if (studentDTO.getName() != null) {
student.setName(studentDTO.getName());
dataUpdated = true;
}
}
if (isEmptyOrBlank(studentDTO.getBirthday())) {
handleBadParam("Bad student birthday");
} else {
if (studentDTO.getBirthday() != null) {
student.setBirthday(studentDTO.getBirthday());
dataUpdated = true;
}
}
// .... 20 other similar if-else statements later ....
// if atleast one parameter updated then date should update
if (dataUpdated) {
student.setLastUpdated(new Date());
}
return student;
}
private boolean isEmptyOrBlank(String name) {
return name != null && (name.isEmpty() || isBlank(name));
}
private void handleBadParam(String messgae) {
throw new IllegalArgumentException(messgae);
}
private boolean isBlank(String name) {
return (name.trim().length() == 0);
}
It seems you are validating your object.
I will not share any code example, I will just share an design opinion. By the way while designing your application, you should follow a design principle. So SOLID design principles is the commonly accepted, and you can apply these principles to your app while designing it.
You may create a class like StudentValidator so it's job must be only validating the Student object. So you realize first principle of solid's single responsibility.
And also that StudentValidator class will have methods which validations you need. And after all that implementations, you can cover in a method for each validation or you may call them when needed line.
Also there are many design patterns to avoid if-else statements via implementing patterns. Like command pattern, using enums etc.
I would strongly recommend to use the Java environment JSR 303 Bean Validation.The javax.validation packages provide developers with a standardized way of doing so. Fields that have to fulfill certain criteria receive the corresponding annotations, e.g. #NotNull, and these are then evaluated by the framework. Naturally, for checking more specific conditions, there is the possibility of creating custom annotations and validators.
You could refer to this https://dzone.com/articles/bean-validation-made-simple.
I have the next doubt. According to good practices of java, how to manage the cases in which the object can not be found and we want to know why.
For example, if someone has problems logging in our system and we want to inform them exactly what is the problem, we cannot return null because we lose the reason for not being able to log in. For example:
public User login(String username, String password) {
boolean usernameEmpty = (credentials.getUsername()==null || credentials.getUsername().isEmpty());
boolean passwordEmpty = (credentials.getPassword()==null || credentials.getPassword().isEmpty());
//getUserPassword return null if doesn't exist an user with username and password return null
User user = getUserPassword(username,password);
if (!usernameEmpty && !passwordEmpty && user!=null) {
LOGGER.info("Found " + username);
} else if (!usernameEmpty && !passwordEmpty && user==null) {
LOGGER.info("There is no such username and password: " + username);
} else if (usernameEmpty) {
LOGGER.info("Username can not be empty ");
} else if (passwordEmpty) {
LOGGER.info("Password can not be empty ");
}
return user;
}
I can think of two options with pros and cons to resolve it.
The first one consists in using Exceptions but I think that is not a good idea use different scenarios than expected like exceptions. For that reason, I discard it.
The second one is involve the object (User) in another object to manage the differents posibilities. For example, use something like this:
public class EntityObject<t> {
//Is used to return the entity or entities if everything was fine
private t entity;
//Is used to inform of any checked exception
private String exceptionMessage;
//getters / setters / ..
}
public EntityObject<User> login(String username, String password) {
boolean usernameEmpty = (credentials.getUsername()==null || credentials.getUsername().isEmpty());
boolean passwordEmpty = (credentials.getPassword()==null || credentials.getPassword().isEmpty());
User user = getUserPassword(username,password);
EntityObject<User> entity = null;
if (!usernameEmpty && !passwordEmpty && user!=null) {
LOGGER.info("Found " + username);
entity = new EntityObject<User>(user);
} else if (!usernameEmpty && !passwordEmpty && user==null) {
entity = new EntityObject<User>("There is no such username and password: " + username);
} else if (usernameEmpty) {
entity = new EntityObject<User>("Username can not be empty ");
} else if (passwordEmpty) {
entity = new EntityObject<User>("Password can not be empty ");
}
return entity;
}
I like more this second option than the first one but i don't like that i have to change the method signature to return a different class (EntityObject) than the usual (User).
What is the usual? How is it usually managed?
many thanks
An exception should be used when there is something exceptional happening in the system. For a normal flow and something that is expected to happen you should avoid using exceptions.
Following the good SOLID principals your method should do just one thing. So if it is a method to find user by username and password I would say the best would be to return null (or empty optional if using optionals). The reason is not lost. Actually it is pretty clear - there is not such user found with the supplied username and password (this reason includes the problem with empty username and it's the user of the method's fault to supply empty username to a login method). Adding complex logic to the method and additional entities for such things will make your code harder to maintain and to understand. This method's job is not to handle validation anyway.
If that class is used by a website or its some kind of API then they can handle the validation (if username or password is empty).
For me, second options look better. Probably, to know what was the error instead of writing messages in java code, you can create enum with possible scenarios and resolve it in the Front-end code, if you really need a message, you can create constructor inside enum to store it. It will simplify support and work with an object in the future. Plus, adding more scenarios will not hurt you much.
Basic version:
public class EntityObject<t> {
//Is used to return the entity or entities if everything was fine
private t entity;
//Is used to inform of any checked exception
private enum auth {
NO_PASSWORD, NO_USERNAME, USER_DOES_NOT_EXIST, SUCCESS
}
}
Version with enum constructor:
public class EntityObject<t> {
//Is used to return the entity or entities if everything was fine
private t entity;
//Is used to inform of any checked exception
private enum auth {
NO_PASSWORD("Password cannot be empty"),
NO_USERNAME("Username cannot be empty"),
USER_OR_PASSWORD_DOES_NOT_EXIST("No such username or password exist"),
SUCCESS("OK");
public String message;
public auth(String message) {
this.message = message;
}
}
}
I would say that the second approach is pretty fine. If I were you I would do that.
If you really don't want to change the return value, you can add another method that checks if a user can log in:
public static final String SUCCESS = "Success"
public String checkLoginError(String username, String password) {
// do all the checks and return the error message
// return SUCCESS if no error
}
Now the login method can then be one line:
return getUserPassword(username,password);
And you can use it like this:
String loginResult = checkLoginError(...);
if (loginResult.equals(SUCCESS)) {
User loggedInUser = login(...)
} else {
// do stuff with the error message stored in loginResult
}
It seems like your problem is stemming from a method which is responsible for multiple concerns.
I'd argue that the login method shouldn't be checking whether these values are blank. There is presumably some kind of UI (graphical or not) which is taking a username and password - this should be the layer performing validation on the user input.
The login method should only be concerned with whether the given credentials match a user in your system or not. There's only two outcomes - yes or no. For this purpose, you can use Optional<User>. It should tolerate the strings being empty as this will never match a user anyway (presumably it's impossible for a user to exist in such a state).
Here's some pseudo-code:
void loginButtonPressed()
{
if (usernameTextBox.text().isEmpty())
{
errorPanel.add("Username cannot be blank");
}
else if (passwordTextBox.text().isEmpty())
{
errorPanel.add("Password cannot be blank");
}
else
{
login(usernameTextBox.text(), passwordTextBox.text());
// assign above result to a local variable and do something...
}
}
public Optional<User> login(String username, String password)
{
Optional<User> user = Optional.ofNullable(getUserPassword(username, password));
user.ifPresentOrElse(
user -> LOGGER.info("Found " + username),
() -> LOGGER.info("Not found")
);
return user;
}
Java's null values are one of the worst aspects of the language, as you cannot really tell if a method is receiving a null value until it happens. If you are using an IDE (I hope so) you can check if it can control whether you are passing a null value where there shouldn't be one (IntelliJ can do this by adding the #NotNull annotation to the method's parameters).
Since it can be dangerous, it is better to avoid passing nulls around, as it will certainly lead to an error as soon as your code gets a bit complex.
Also, I think it would be reasonable to check for null values only if there is a concrete chance that there could be one.
If you want to express that a value can be present or not, it's better to use Optional<T>. If, for some reason, a null value could be passed instead of a real value, you could create an utility method whose only concern is to verify that the parameters are correct:
public Optional<EntityObject<User>> login(String username, String password) {
//isNotNull shouldn't be necessary unless you can't validate your parameters
//before passing them to the method.
//If you can, it's not necessary to return an Optional
if (isNotNull(username, password)) {
//Since I don't know if a password must always be present or not
//I'm assuming that getUserPassword returns an Optional
return Optional.of(new EntityObject<User>(getUserPassword(username,password).orElse(AN_EMPTY_USER)));
} else {
return Optional.Empty();
}
}
Anyway, I think that validating the input shouldn't be a concern of the login method, even if you don't want to use Optional; it should be done in another method instead.
Let's imagine, that we have a process, which accepts data of the following type:
{"date":"2014-05-05", "url":"http://some.website.com","counter":3}
This data should be validated formally: value of date should be a
parseable date, url should also conform the normal url syntax.
Also, this data should be validated logically: date should be in the future, url should be an accessible
address, returning 200 OK.
To make it clean, one must separate those two validation routines into different units (classes, utils, whatever). The desired final behaviour, however, must give user clear understanding of ALL violations, that are present in data. Something like:
{"Errors":[
"Specified date is not in the future",//Formal validation failed
"Specified URL has invalid syntax"//Logical validation failed
]}
I have seen some implementations of the required behaviour, but they
use those make use of Error objects and are full of checks like
Error.hasErrors() or error==null, which does not look elegant.
I have also seen the implementation of javax.validation, which gives you all violations on all field at once. Same approach could be implemented for content validation, but I am not sure, that this is the best way to do this.
Question: what is the best practice for handling multiple exceptions/violations of various nature?
UPD: short digest of answers: collect Violations, build an Exception, containing their context, cause and description, use an interceptor to render. See reference links from answers:
http://beanvalidation.org/1.0/spec/ JSR 303 specification
http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/validation.html Spring Bean Validation
http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html Java EE validation
Which Design Pattern To Use For Validation
Why not use exceptions as regular flow of control?
You can do the following:
define an abstract Check class, as follows:
public abstract class Check {
private final List<Check> subChecks = new ArrayList<Check>();
public Check add(Check subCheck) { subChecks.add(subCheck); return this }
public void run(Data dataToInspect, List<Error> errors) {
Error e = check(dataToInspect);
if (e != null) {
errors.add(e);
return;
}
for (Check subCheck : subChecks) {
subCheck.run(dataToInspect, errors);
}
}
// Returns null if dataToInspect is OK.
public abstract Error check(Data dataToInspect);
}
class Data is the class holding the data (that needs to be checked). Can be a String, a JSON object, what have you.
class Error represents a problem detected in the data should be roughly something like:
public class Error {
private String problem;
public Error(String problem) { this.problem = problem }
public String getProblem() { return problem }
// maybe additional fields and method to better describe the detected problem...
}
You then have code that runs the check against piece of data:
public class Checker {
private final List<Error> errors = new ArrayList<Error>();
private final List<Check> checks = new ArrayList<Check>();
public Checker() {
checks.add(new DateIsParsableCheck().add(new DateIsInTheFurutreCheck());
checks.add(new UrlIsWellFormed().add(new UrlIsAccessible());
checks.add();
..
}
public void check(Data d) {
for (Check c : checks) {
Error e = c.run(d, errors);
if (e != null)
errors.add(e);
}
}
}
Slightly changed my original answer. In the current answer there is the notion of subchecks: if a check called x has a subcheck called y then the y check will run only if the x check succeeded. For instance, if the Date is not parseable there is no point to check it it is in the future.
In your case I think that all/most logical check should be sub-checks of a formal check.
I don't think there is a best practice, because it depends on what you try to achieve. In my opinion, exceptions and their messages should not be used to be displayed directly to the user. Exceptions are way too technical and do depend heavily on the context where they get thrown.
Hence, my approach would be to design a container type which collects all the exceptions thrown by your validations. Those exceptions should preserve as much of the context as possible (not in form of an exception message, but in form of fields passed into the constructor). Provide getter methods to make those fields (properties) accessible. When rendering the view, you may iterate over all entries of your container and generate a proper, human readable, i18n message.
Here is some pseudo-code as requested by the comment of #AlexandreSantos. It is not polished nor proven, just my first draft. So do not expect excellent design. It's just an example how it could be implemented / designed:
public static void main(String[] args) {
Violations violations = new Violations();
Integer age = AgeValidator.parse("0042", "age", violations);
URL url = UrlValidator.parse("http://some.website.com", "url", violations);
}
// Validator defining all the rules for a valid age value
public class AgeValidator {
// Collection of validation rules for age values
private static final Collection<Validator<String>> VALIDATORS = ...;
// Pass in the value to validate, the name of the field
// defining the value and the container to collect all
// violations (could be a Map<String, ValidationException>)
//
// a return value of null indicates at least one rule violation
public static Integer parse(String value, String name, Violations violations) {
try {
for (Validator<String> validator : VALIDATORS) validator.validate(value);
} catch (ValidationException e) {
violations.add(name, e);
}
return violations.existFor(name) ? null : Integer.parseInt(value);
}
}
I have answered this previously Here
The answer marked as good is an example of the Composite pattern being applied to validation (almost)
There are, of course, tons of frameworks for this. Something clever you could do, that I have used to great effect, is to use an aspect + a validator or make sure whole swaths of new and existing code get checked auto-magically.
#Aspect
public class DtoValidator {
private Validator validator;
public DtoValidator() {
}
public DtoValidator(Validator validator) {
this.validator = validator;
}
public void doValidation(JoinPoint jp){
for( Object arg : jp.getArgs() ){
if (arg != null) {
Set<ConstraintViolation<Object>> violations = validator.validate(arg);
if( violations.size() > 0 ){
throw buildError(violations);
}
}
}
}
private static BadRequestException buildError( Set<ConstraintViolation<Object>> violations ){
Map<String, String> errorMap = new HashMap<String, String>();
for( ConstraintViolation error : violations ){
errorMap.put(error.getPropertyPath().toString(), error.getMessage());
}
return new BadRequestException(errorMap);
}
}
Here is a snip of bean config
<aop:config proxy-target-class="true">
<aop:aspect id="dtoValidator" ref="dtoValidator" order="10">
<aop:before method="doValidation"
pointcut="execution(public * com.mycompany.ws.controllers.bs.*.*(..))"/>
</aop:aspect>
</aop:config>
Now all of your controller methods will have that validation code applied here and into the future.
Designing it using exceptions will work, but you will have to write a whole framework to deal with exceptions, many of which can't be handled by your exception interceptor. If you feel the coding itch, then go for it. My advice would be to have different classes of exceptions. Some of them would be critical exceptions, some would be just warnings... you got the picture.
You could (I hope you do) use a proven framework that can handle that beautifully. I speak of JSR 303 and Bean Validation through Spring: http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/validation.html
It takes a while to get used to, but it will pay you back 1000 fold.
I would simply pass around a list of all the errors. The items in the list may not be just exceptions, but rather some objects wrapping more information about the errors, such as name of wrong parameter, its wrong value, position of the error in the string, type of validation (formal, ligical), ID of the error message for localized display to user... Each method on the processing path may append to the list.
Is it possible to define optional parameter when rendering an scala template in Play Framework 2?
My controller looks like this:
public static Result recoverPassword() {
Form<RecoveryForm> resetForm = form(RecoveryForm.class);
return ok(recover.render(resetForm));
// On success I'd like to pass an optional parameter:
// return ok(recover.render(resetForm, true));
}
My Scala template looks like this:
#(resetForm: Form[controllers.Account.RecoveryForm], success:Boolean = false)
Also tried:
#(resetForm: Form[controllers.Account.RecoveryForm]) (success:Boolean = false)
In both cases i got "error: method render in class recover cannot be applied to given types;"
From Java controller you can't omit assignation of the value (in Scala controller or other template it will work), the fastest and cleanest solution in this situation is assignation every time with default value, ie:
public static Result recoverPassword() {
Form<RecoveryForm> resetForm = form(RecoveryForm.class);
if (!successfullPaswordChange){
return badRequest(recover.render(resetForm, false));
}
return ok(recover.render(resetForm, true));
}
Scala template can stay unchanged, as Scala controllers and other templates which can call the template will respect the default value if not given there.
BTW: as you can see, you should use proper methods for returning results from Play's actions, see ok() vs badRequest() also: forrbiden(), notFound(), etc, etc
You can also use flash scope for populating messages and use redirect() to main page after successful password change, then you can just check if flash message exists and display it:
public static Result recoverPassword() {
...
if (!successfullPaswordChange){
return badRequest(recover.render(resetForm, false));
}
flash("passchange.succces", "Your password was reseted, check your mail");
return redirect(routes.Application.index());
}
in ANY template:
#if(flash.containsKey("passchange.succces")) {
<div class="alert-message warning">
<strong>Done!</strong> #flash.get("passchange.succces")
</div>
}
(this snippet is copied from Computer Database sample for Java, so you can check it on your own disk)