How to handle "Save as draft" with Hibernate validation annotations - spring

Say I have a simple form with the following field the user has to fill in:
name
surname
birth date
address
The data needs to be saved in a database table with the same fields/columns. All the columns are not nullable.
The form offers two buttons: "Save" and "Save as draft" to let the user finish compiling the form later.
The first will check if all the fields are correctly filled whereas the second doesnt make any check other than "cannot insert number in name field".
I tend to use Hibernate Validation annotations on my DTO, but in this case will break the function "Save as draft".
How would you handle this scenario?
Technologies I'm using: Spring Boot/MVC to expose the REST service consumed by frontend, hibernate/Spring DATA to save data to database.

You can use a validation function instead of annotations directly on the attributes. That way your validation can have some logic in it.
#Value
class MyDto{
String name;
String surname;
DateTime birthdate;
Address asdress;
boolean draft;
#AssertTrue
private boolean validateInstance(){
if(!isDraft()){
// do validation
}
return true;
}
}

Create an interface for your entry and create two implementations of that interface.
One being the actualEntry with the annotations.
The other being the draft without those annotations.

Related

Spring boot + JPA(Hibernate) Edit partial entity fields

all.
I have following simple form in which I want to edit the entity. The problem is that I have some fields which I don't want to be edited. For example (Image file path).
As it is now, I have the service method -
public void addOrModifyLayout(Layout layout){
if(layout.getId() == null){
layoutRepository.save(layout);
}
else {
Layout modifiedLayout = new Layout();
modifiedLayout.setId(layout.getId());
modifiedLayout.setName(layout.getName());
modifiedLayout.setStatus(layout.getStatus());
modifiedLayout.setExhibitor(layout.getExhibitor());
layoutRepository.save(modifiedLayout);
}
}
As you can see, every field that I want to be able to be edited, I should explicitly put it in the service. Can I use some mapper or trick to update only some fields that are in the view (form) ? How you handle this kind of issues?
You can either
store all the entity fields in hidden inputs (e.g. imageFilePath hidden input). So you can store on UI all the entity fields and get them back to assign to the entity.
OR
Avoid new entity creation but retrieve existing one and fill only necessary fields.
Layout modifiedLayout = layoutRepository.getById(layout.getId());
modifiedLayout.setName(layout.getName());
modifiedLayout.setStatus(layout.getStatus());
modifiedLayout.setExhibitor(layout.getExhibitor());
layoutRepository.save(modifiedLayout);

Spring MVC and annotations, how to do a validator in the case of a form that will contain different fields depending of a combo box

I am trying to accomplish the following:
I have a form that starts with a combo box, let's say that the user will have to pick either "Student" or "Teacher".
Both "Student" and "Teacher" will have the same fields displayed in the form, but if "Teacher" is checked, I will have more fields being displayed (that are hidden at first and that I will show with jQuery when the user select "Teacher").
The problem is that I want those fields to be mandatory only if "Teacher" is selected.
I have no idea to manage that, I don't think it's gonna be possible using annotations such as:
#NotBlank
private String teacherCourse;
since this field will always be blank when the user will have selected the "Student" radio button.
Any idea? Can I do a custom validation method and how?
I've taken two approaches with this in the past.
Use an enum field on the submission to determine which type of validation to perform. This is flexible and allows for any number of custom validation methods.
An alternative is to use a base command object which both student and teacher classes extend. This allows both types to extend and override validation and fields. This requires that separate methods are used to bind each type.
You could use validation groups to differentiate between constraints applying to both entities and those applying to only one of them:
public interface TeacherConstraints {}
#NotBlank(groups=TeacherConstraints.class)
private String teacherCourse;
When validating your object, specify the group to validate depending on the type selected in your combo box:
//teacher
Set<ConstraintViolation<Object>> violations = validator.validate(object, TeacherConstraints.class);
//student
Set<ConstraintViolation<Object>> violations = validator.validate(object, Default.class);
You can use javascript or JQuery for front side validation... depending upon your combo box value. If it's a teacher or student
function validate(){
var combox_value = document.getElementbyID("combo_box").value;
if(combox_value == "Teacher"){
//Validate for Teacher fields
var input_text1 = document.getElementbyID("input_text"2).value;
if(input_text1=="" || input_text1==null){
alert("Field cannot be empty");
return false;
}
return true;
}
else if(combox_value == "Student"){
//Validate for Student fields
var input_text2 = document.getElementbyID("input_text2").value;
if(input_text2=="" || input_text2==null){
alert("Field cannot be empty");
return false;
}
return true;
}
}
For JQuery try these links for live examples...
http://speckyboy.com/2009/12/17/10-useful-jquery-form-validation-techniques-and-tutorials-2/
http://www.jeasyui.com/tutorial/form/form3.php
http://www.camcloud.com/blog/jquery-form-validation-tutorial

Complex Spring form validation using javax.validation

What I'm trying to accomplish is:
Have a bean backed form being validated, for example using the following class
public class PersonForm {
#NotNull
String name;
List<Long> interests;
// This attribute is not filled out in the form
List<Interest> realInterests;
}
So, "name" and "interests" come from the web form. "name" has some constrains (NotNull) and using #Valid does what it is supposed to do.
"interests" is a list of Interest ids.
After doing the initial validation of the "name" I fill out the List collection.
#CustomValidInterest
public class Interest {
Long id;
String name;
boolean available;
}
I want to validate this structure afterwards. "#CustomValidInterest" is a custom validation annotation.
I can do a 2-stage validation using do this with Validation Groups.
The problem is, if some "Interest" object is not valid I want to associate the error message with the "interests" field (List< Long > type), so when I retrieve the form errors the error is associated with the right field.
Maybe I'm trying to use validation the wrong way. I was trying to avoid having a bunch of programmatic comparisons which filled errors manually.
Answering my own question, this is achievable using PropertyEditors. The form might return a List< Long > but the form object can have only a List < Interest > which is built using said Property mapper. After that a #Valid on that list should validate any constraints that "Interest" enforces.

Play framework 2: one model approach

The problem:
When programming with play framework I feel that I'm stumbling with same problem than in many times at the past which is creating several models of the same type just because I want to add, update or use different data about certain model in different use cases.
Let me explain, lets consider of a example where I have 2 different views: register and login
I would have following User model:
/**
* Example User class (simple annotations for demo purposes).
*
*/
#Entity
public class User {
#Id
public Long id;
#Required
public String email;
#Required
public String password;
#Required
public String firstName;
#Required
public String lastName;
}
In case of registering: I would have all corresponding fields in register.scala.html : email, password, firstName, lastName - because I will need them all when I register, right?
But also I would want to use repeatPassword field to confirm that user has typed password correctly, so I would add this into User model:
#Required
#Transient
public String repeatPassword;
Ok, then I would extend this model to have repeat password confirmation check in order to correct my "automatic" validations when form is submitted, like this:
public String validate() {
if(!password.equals(repeatPassword)) {
return "Passwords doesn't match.";
}
return null;
}
}
So even now I would have one extra attribute repeatPassword which is not persisted to database but used within registration.
Problem #1: Our model starts to go confusing piece by piece.
In case of login: I would want to use same model because its a User which is trying to sign in, right? But instead of all the fields I would only need email, password.
Problem #2: My User model cant be used in login because its already customized to be used within registration - I would need to move repeatPassword and validate() method to separate UserRegistation model, plus duplicate firstName lastName etc. fields or mix using both User and UserRegistration model within registration and to render two different forms to same registration view = confusing.
Problem #3: My login page cant use User model because it has annotations in place, if I dont add all the necessary fields like firstName, lastName etc. I will get errors. Again, I would need to create separate UserLogin model just because I want to login to work.? Example below:
public class UserLogin {
#Required
public String email;
#Required
public String password;
public String validate() {
if(User.authenticate(email, password) == null) {
return "Invalid user or password";
}
return null;
}
}
So very fast, I would have 3 different models just to represent User, one of them is persisted to database and two others is used to validate errors when we are completing login and registration functionality at template side.
So my question is: How on earth I should begin to solve this mess? code complexity is rising very fast :) Should I create separate models.template and models.database packages where template models are only ones within annotations and in case of no errors I start to fill real model before saving or updating its info to database? I need desperately answers from you guys/girls, Can we make one model approach? thnx in advance.
I'll start from the end: you don't need to use whole model for changing password or loggin-in (also you don't need to create separate, 'non-persisted' sub-models), although Form<YourModel> is useful while filling large objects, you can just avoid them and rely on common DynamicForm.
In such case of course it won't use constraints added with annotations to the model's fields but you can validate them manually.
For an example: in registration form you can check if #Required fields like email, firstName, lastName exists (tip: also add MinLength and MaxLength constraints), but you should remove #Required annotation from password field.
Next after checking if the form hasn't any errors you can check if password and repeatedPassword are the same and it they are identical you can also add some individual (advised) strength check - most probably it wouldn't be possible with the annotations in the model.
In case of logging form the thing is ever easier: using DynamicForm data just try to find existing User with given password if result is null that means, the user doesn't exists or password is invalid.
Finally, tip: There is ready-to-use, full-stack authentication and authorisation module available for Play 2.0 by Joscha Feth (and I'm huge advocate of this solution.)

Few questions... ModelState.IsValid and Grouped CheckBox Values

Using ASP.NET MVC when I create my model, then a controller based on the model with CRUD operations, the CRUD views are generated. I added some code using Fluent API to require certain fields but for some reason the ModelState.IsValid passes even when these fields are not completed. What determines whether this passes or not? I thought it was based on your model property data types and other things like being required or maxlength, etc....
Also, I have manually added code to grab a list of Categories from the database and generate a checkbox for each one in the View. This is a navigation property for the Project model where there is a many-many relationship. To get the group of checked values in the Create(Project project) method in the controller I use:
var selected = Request["categories"].Split(',');
This however, throws the classic Object reference not set to an instance of an object error if no values are checked. So what I want to know is, how can I determine that this does not have any values so I can do something else once detected?
I added some code using Fluent API to require certain fields but for
some reason the ModelState.IsValid passes even when these fields are
not completed.
ASP.NET MVC doesn't know anything about the Fluent API of Entity Framework and doesn't evaluate this configuration. You only can use the data annotations which MVC will recognize:
[Required]
public string SomeProperty { get; set; }
...how can I determine that this does not have any values so I can do
something else once detected?
Not sure if I understand it correctly but I'd say:
var categories = Request["categories"];
if (categories != null)
{
var selected = categories.Split(',');
// ...
}
else
{
// do something else
}

Resources