JSF/Primefaces doesn't validate #AssertTrue - validation

my entity class look like this:
public class TimeFrame implements Serializable {
#NotNull
private Date startTime;
#NotNull
#Future
private Date stopTime;
To have the right order I added:
#AssertTrue(message="Wrong order")
public boolean isTimeFrameValid(){
return this.startTime.before(stopTime);
}
Now, JSF/Primefaces should validate this directly after input.
<p:calendar id="aucstop" required="true" pages="2" value="#{transportbean.stopTime}" >
<p:ajax event="dateSelect" />
<f:validateBean/>
</p:calendar>
For example, when putting a past date into "StopTime" I got immediately a message. The "isTimeValid"-Mothod however is only validated when the whole object ist being created. Any ideas how to validate this directly after input?
GF 3.1.1 PrimeFaces 3.4

Related

Change of multiple select handling in Spring Boot 2.3.1

Just faced a wired change of behavior after upgrading the Spring Boot version from 2.3.0 to 2.3.1
There is such a simple Thymleaf view with multi-select control
<div class="form-group">
<label for="roles">Roles</label>
<select multiple class="form-control" id="roles" th:field="*{roles}" required>
<option th:each="role : ${roles}"
th:text="${role.name}"
th:value="${role.id}"
th:selected="${user.roles?.contains(role)}"></option>
</select>
</div>
and POST handling controller method
#PostMapping
public String saveUser(#Valid User user, BindingResult bindingResult) {
logger.info("Save user method");
userService.save(user);
return "redirect:/user";
}
With version 2.3.0 if I submit the form with some roles selected I got them as a correct set of roles in roles field.
But with version 2.3.1 I got an incorrect list of roles. Id field in role object is empty in all of them and the name field is filled with id value. Looks like some Spring MVC or Thymleaf configuration is changed in this version but I see nothing obvious in the release notes here https://github.com/spring-projects/spring-boot/releases/tag/v2.3.1.RELEASE
I understand that this problem could be resolved by implementing custom Formatter but why it works without it with Spring Boot 2.3.0.
User class is like that
public class User {
private Long id;
private String name;
private String password;
private Set<Role> roles;
// getters, setters, etc.
}
Role class
public class Role implements Serializable {
private Long id;
private String name;
// getters, setters, equals, hashcode, etc.
}

Spring form insert data in model object inside base domain model

I have a model like this:
public class User{
private int id;
private City city;
//Getter - setters
}
public class City{
private int id;
private String name;
//Getter - setters
}
Now on JSP I want to show a form for User model, which should ask for user's city in a dropdown, and corresponding city object should get stored in city object in User model.
For normal fields, I know we can write something like this:
<form:input path="name" />
But how can we bind a model object inside our base model? And how Spring will know, which object it should store in that after user selects any city?
Pretty easy, you need #modelAttribute in your controller method (or simply add it to model) on loading the form and use in your case path should be city.name
Your question is more like how to reference a submodel, spring follows the bean path, in your case, if you wanna post a city with user object, you just need to do this
<form:form method="POST" commandName="user">
<form:input path="city.name" />
<form:input path="attribute of user" />
</form:form>

Spring + hibernate + form

I have an User entity:
#Entity
#Table(name = "user")
public class User implements Serializable{
private enum Sex {MALE, FEMALE};
#Id #GeneratedValue
private Long id;
#NotNull
private String name;
#NotNull
private String password;
}
Controller:
#Controller
public class HomeController {
#RequestMapping("/addUser")
public String showHomePage(Map<String, Object> map) {
map.put("user", new User());
return "addUser";
}
and form in jsp file
<form:form method="post" action="add" commandName="user">
<form:input path="name"/>
<form:input path="password"/>
<form:input path="confirm-password"/>
</form:form>
This form generates error because there is no confirm-password field in User.class. I could of course add confirm-password field as #Transient to User.class, but what if I would like to add captcha field to my form. Is there a different way to add additional field to form?
It is not a good practice to use your models as form entities. You should have a bean or form class to get the data from the view and another for the model.
Reason is that they have different responsibilities thus needing to to be mapped to different classes. They are often very similar, but that separation promotes a cleaner coding and avoids security breaches, as a user could try to use your model variables from the view by using a request tamperer for example(like fire bug).
These small differences between them like the one you listed above justify the creation of another class.

Compare two fields that use same class

I have two input fields fromDate and toDate which are instances of Date class.
The Date class uses custom Date validator which validates the month, day and year fields
contained in the date field.
The custom date validator is specific for each date i.e, fromDate and toDate.
I need to compare the month, day or year fields of fromDate with toDate.
If the fromDate is greater than toDate, a validation message has to displayed.
Update:
The fromDate and toDate are two custom date components as below
<eg:dateField id="inpFromDate" value="#{mrBean.fromDate}" .... />
<eg:dateField id="inpToDate" value="#{mrBean.toDate}" .... />
fromDate and toDate are instances of Date class which is
public class Date {
private String mm;
private String dd;
#customDateValidator //Validates each date field
private String yyyy;
//constructors
//getters and setters
How would you implement the validator in this case where each date already has a validator
Yes, you can! Suppose you have the following PrimeFaces's input fields:
<p:calendar id="from" value="#{mrBean.fromDate}" binding="#{from}" >
<p:ajax process="from to" update="toDateMsg" />
</p:calendar>
<p:calendar id="to" value="#{mrBean.toDate}" >
<f:attribute name="fromDate" value="#{from.value}" />
<f:validator validatorId="validator.dateRangeValidator" />
<p:ajax process="from to" update="toDateMsg" />
</p:calendar>
<p:message for="to" id="toDateMsg" />
This should be your Validator:
#FacesValidator("validator.dateRangeValidator")
public class DateRangeValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
if (value == null || component.getAttributes().get("fromDate") == null) return;
Date toDate = (Date) value;
Date fromDate = (Date) component.getAttributes().get("fromDate");
if (toDate.after(fromDate)) {
FacesMessage message = new FacesMessage("Invalid dates submitted.");
message.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(message);
}
}
}
Note that I am using PrimeFaces's <p:calendar> component to write my example because the properties binded to this component will automatically be converted to Date object before being validated. In your program, you may have your own Converter to convert String to Date.

How can I validate a complex model object in Spring 3 using #Valid annotations?

I have a model object modelling a purchase order. The purchase order has a few fields (such as ID and date) and a list of line-items as ArrayList. I can validate the parent purchase order ok, but it chokes when validating the line-items.
Can anyone help me with validation of complex objects? If I cannot validate complex objects auto-magically, how can I write a custom validator that relies upon the constraint annotations in the parent and then iterates over the child line-items? This Validator instance needs to be able to call something.validate(purchaseOrder) and (for each line-item) something.validate(lineItem). Where do I get "something" from?
I have specified <mvc:annotation-driven /> in dispatcher-servlet. I am not using #InitBinder. And I am using #Valid annotation for validation in controller's method like
#RequestMapping(params="confirmPurchaseOrder")
public String confirm(
#ModelAttribute("purchaseOrder") #Valid PurchaseOrder purchaseOrder,
BindingResult result,
#RequestParam("account") String accountString,
#RequestParam("division") String divisionString,
Model model)
{
if (result.hasErrors()) {
return PURCHASE_ORDER_CREATE_VIEW;
}
The domain classes look like this: -
public class PurchaseOrder implements Comparable<PurchaseOrder> {
/** Based on GUID */
private String id;
/** SOP */
#NotNull
private Integer SOP;
/** Reference from client */
#NotBlank
private String purchaseOrderReference;
/** PO date */
#DateTimeFormat(style="S-")
#NotNull
private Date date;
#Valid
private final Collection<LineItem> lineItems = new ArrayList<LineItem>();
And
public class LineItem {
...Elided
/** Generated from GUID */
private String id;
#NotNull
#DateTimeFormat(style="S-")
#Future
private Date expiry;
private String softwareVersion;
#NotNull
#NumberFormat(style = Style.NUMBER)
#Min(1)
private Integer licenceCount;
When committing a Purchase Order with an empty expiry date, I get the following exception:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.beans.InvalidPropertyException: Invalid property 'lineItems[]' of bean class [com.nit.ols.domain.PurchaseOrder]: Invalid index in property path 'lineItems[]'; nested exception is java.lang.NumberFormatException: For input string: ""
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:730)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:634)
javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
In your PurchaseOrder class, try changing your lineItems collection to a List. It looks like you are having the same problem addressed in this question.
It's like David said, declaring lineItems of type List should do the trick. In Hibernate Validator 4.2.0 CR1 (not yet released atm, you could use the latest snapshot build if you are interested) also Collection should work, see HV-468 for more details.

Resources