hibernate validation not working while one-to-one mapping in between two entities - spring

During form submission, if there is any validation error then form shows the errors messages under the fields. But the actual problem is in another place. I have two entities User and UserDetails. These entities are mapped with each other by bidirectional one-to-one mapping. Validation is working only with the User entity fields but not with the UserDetails entity.
Spring - 5.0.2`
Hibernate - 5.2.10
User.java
#Entity
#Table(name="users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#NotEmpty(message="{common.error.msg}")
private String first_name;
#NotEmpty(message="{common.error.msg}")
private String last_name;
#NotEmpty(message="{common.error.msg}")
private String status;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "user", fetch = FetchType.LAZY)
private UserDetails userDetails;
//Getter and setter methods
}
UserDetails.java
#Entity
#Table(name="user_details")
public class UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int user_id;
#NotEmpty(message="{common.error.msg}")
private String address;
#NotEmpty(message="{common.error.msg}")
private String mobile;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id")
private User user;
//Getter and setter methods
}
Get and Post methods in the controller class
#GetMapping(value="/create")
public String loadUserForm(Model model) {
model.addAttribute("command", new User());
return "backend/oms/user/form"; //JSP
}
#PostMapping(value="/create")
public String Save(#Valid #ModelAttribute("command") User user, BindingResult br, Model model, HttpSession session, RedirectAttributes ra) {
if(br.hasErrors()) {
return "backend/oms/user/form"; //JSP
} else {
try {
int id = userService.save(user);
if(id > 0) {
ra.addFlashAttribute("flash_msg", "ok|User added!");
return "redirect:/oms/user/edit/"+id;
} else {
return "backend/oms/user/create"; //JSP
}
} catch (ConstraintViolationException ex) {
model.addAttribute("err", "Something wrong! Please try again.");
return "backend/oms/user/form"; //JSP
}
}
}
messages.properties
common.error.msg=This field is required!
form.jsp
<form:form action="/oms/user/create" method="post" modelAttribute="command">
<label>First Name</label>
<form:input path="first_name" class="form-control" placeholder="First Name" value="" />
<form:errors cssClass="error" path="first_name" />
<label>Last Name</label>
<form:input path="last_name" class="form-control" placeholder="Last Name" value="" />
<form:errors cssClass="error" path="last_name" />
<label>Mobile</label>
<form:input path="userDetails.mobile" class="form-control" placeholder="Mobile" value="" />
<form:errors cssClass="error" path="userDetails.mobile" />
<label>Address</label>
<form:textarea path="UserDetails.address" class="form-control" placeholder="Address" value="" />
<form:errors cssClass="error" path="userDetails.address" />
<label>Status</label>
<form:select class="form-control" path="status">
<option value="">Choose...</option>
<option value="E">Enable</option>
<option value="D">Disable</option>
</form:select>
<form:errors path="status" cssClass="error"/>
<input type="submit" class="btn btn-primary" value="Save" />
</form>
Please see the screenshot
As you can see the image only fields from the User entity is validating but fields those are from the UserDetails are not validating. Please help.

It is solved now. #Valid annotation solved my problem. I need to put #Valid annotation before the entity variable declaration like below --
#OneToMany(mappedBy="majorHead", cascade = CascadeType.ALL)
#Valid
private List<MinorHead> minorHead = new ArrayList<MinorHead>();

Related

Select thymeleaf doesn't create a value in my db

I have a project of library in spring with thymeleaf and MySQL. I have a form of book in which I have select option with author and other with editorial. I receive a list of all of them from my ddbb, but when I submit in the button the data doesn't create a registry in my ddbb, But when I use input its work fine.
here is the code
HTML
<div class="form-group">
<label class="col-sm-2 col-form-label">Autor</label>
<div class="col-sm-6">
<select th:field="*{autor}" id="provincia">
<option th:each="autor:${autores}" th:text="${autor.nombre}"
th:value="${autor.id}" />
</select>
<!-- <input type="text" th:field="*{autor.id}" class="form-control" th:errorclass="'form-control alert-danger'" />-->
<!-- <small class="form-text text-danger" th:if="${#fields.hasErrors('autor.id')}" th:errors="*{autor.id}"></small> -->
</div>
</div>
<div class="form-group">
<label class="col-sm-2 col-form-label">Editorial</label>
<div class="col-sm-6">
<select th:field="*{editorial}">
<option th:each="editorial:${editoriales}"
th:text="${editorial.nombre}" th:value="${editorial.id}" />
</select>
<!-- <input type="text" th:field="*{editorial.id}" class="form-control" th:errorclass="'form-control alert-danger'" />-->
<!-- <small class="form-text text-danger" th:if="${#fields.hasErrors('editorial.id')}" th:errors="*{editorial.id}"></small> -->
</div>
</div>
Here is the controller
#RequestMapping(value = "/form_lib")
public String crearLibro(Model model) {
Libro libro = new Libro();
model.addAttribute("libro", libro);
model.addAttribute("titulo", "Formulario crear Libro");
model.addAttribute("autores", autorDao.listaAutores());
model.addAttribute("editoriales", editorialDao.listaEditoriales());
return "form_lib";
}
#RequestMapping(value = "/form_lib", method = RequestMethod.POST)
public String guardarLibro(#Valid #ModelAttribute Libro libro, BindingResult result, Model model,
#RequestParam("file") MultipartFile imagen, RedirectAttributes attributes) {
if (result.hasErrors()) {
model.addAttribute("titulo", "Formulario de Libro");
model.addAttribute("libro", libro);
System.out.println("errrorrrr");
return "listar_libro";
}
if (!imagen.isEmpty()) {
=Paths.get("src//main//resources//static/images");
String rutaAbsoluta = "//home//marce//Documentos//imagen";
try {
byte[] bytesImg = imagen.getBytes();
Path rutaCompleta = Paths.get(rutaAbsoluta + "//" + imagen.getOriginalFilename());
Files.write(rutaCompleta, bytesImg);
libro.setImagen(imagen.getOriginalFilename());
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(libro.toString());
libroDao.guardarLibro(libro);
return "redirect:/form_lib";
}
Here is the entity
#Entity
#Table(name = "libros")
public class Libro implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_libro")
private int id;
#Column(name = "isbn")
private long isbn;
#Column(name = "titulo")
private String titulo;
#Column(name = "anio")
private int anio;
#Column(name = "ejemplares")
private int ejemplares;
#Column(name = "ejemplaresp")
private int ejemplaresPrestados;
#Column(name = "ejemplaresr")
private int ejemplaresRestantes;
#Column(name = "alta")
private boolean alta;
#Column(name = "imagen")
private String imagen;
#OneToOne
#JoinColumn(name="id_autor")
private Autor autor;
#OneToOne
#JoinColumn(name="id_editorial")
private Editorial editorial;

JasperException: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'user' available as request attribute

I have two Data Model : User and Car, User can have many cars , so this is the User Class :
#Entity
#Table(name="APP_USER")
public class User implements Serializable{
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
......
#OneToMany(mappedBy="user",cascade=CascadeType.ALL)
private Set<Car> cars = new HashSet<Car>();
Car.java :
#Entity
public class Car implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id ;
.....
#ManyToOne(optional=false)
#JoinColumn(name="user_fk")
private User user;
In the carController , I have the method to add a new Car for one user :
#Controller
#RequestMapping("/cars")
public class CarController {
#Autowired
CarService carService;
#Autowired
UserService userService;
#RequestMapping(value={"/list"},method=RequestMethod.GET)
public String listCars(ModelMap model){
List<Car> cars = carService.allCars();
model.addAttribute("cars", cars);
return "car"; }
#ModelAttribute("utilisateurs")
public List<User> allUsers(){
List<User> utilisateurs = userService.findAllUsers();
return utilisateurs;
}
#RequestMapping(value={"/newCar"},method=RequestMethod.GET)
public String newCar(ModelMap model){
Car car = new Car();
model.addAttribute("car",car);
return "carRegistration";
}
#RequestMapping(value={"newCar"},method=RequestMethod.POST)
public String newCar(#Valid Car car, BindingResult result,ModelMap model){
if (result.hasErrors()) {
return "registration";
}
carService.save(car);
model.addAttribute("car",car);
return "redirect:/cars/list";
}
Finally , in the view , the form is :
<form:form method="POST" modelAttribute="car"
class="form-horizontal">
<form:input type="hidden" path="id" id="id" />
<div class="control-group">
<label class="control-label">Libelle</label>
<div class="controls">
<form:input type="text" path="libelle" id="libelle" style="height:4%" />
</div>
</div>
<div class="control-group">
<label class="control-label">Registration</label>
<div class="controls">
<form:input type="text" path="registration" id="email" />
</div>
</div>
<div class="control-group">
<label class="control-label">Utilisateur</label>
<div class="controls">
<form:select path="user" items="${utilisateurs}" itemValue="id" itemLabel="lastName" style="margin-left: 4%;"></form:select>
</div>
</div>
<div class="form-actions">
<input type="submit" value="Validate" class="btn btn-success" />
</div>
</form:form>
I can get the view , but when I click on button submit , I get this error :
Neither BindingResult nor plain target object for bean name 'user' available as request attribute.
I think there is a problem with the select item of users !!
Have you provided any Spring converter or formatter for User ?
applicationContext.xml:
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="my.project.StringToUser"/>
<bean class="my.project.StringToRole"/>
</list>
</property>
</bean>
<mvc:annotation-driven conversion-service="conversionService" />
It will convert User id to User object.
my.project.StringToUser:
import org.springframework.core.convert.converter.Converter;
public class StringToUser implements Converter<String, JUser> {
#Autowired
private UserService userService;
#Override
public JUser convert(String source) {
long id = Long.valueOf(source);
return userService.get(id);
}
}
the error :
WARNING: Failed to bind request element: org.springframework.beans.TypeMismatchException:
Failed to convert value of type [com.websystique.springmvc.model.User] to required type [com.websystique.springmvc.model.User];
nested exception is org.springframework.core.convert.ConversionFailedException:
Failed to convert from type [com.websystique.springmvc.model.User] to
type [#org.springframework.web.bind.annotation.ModelAttribute #javax.validation.Valid com.websystique.springmvc.model.User]
for value 'User [id=null, ssoId=alaa, password=alaa1991, firstName=, lastName=, email=, userProfiles=null, accounts=null, userDocuments=[], cars=[], documents=[]]';
nested exception is java.lang.ClassCastException:
com.websystique.springmvc.model.User cannot be cast to java.lang.String

Validation in spring

I am using spring mvc and hibernate.I have a form which has three fields id,sum and sum_amount .I have a table in database which has 2 column "id" and "Amount".Now I want to persist amount field in that table if sum(Amount) of a id attribute less than sum_amount field specified in form otherwise it will show an error.How can i do that validation?
<form action="join" method="POST" ajaxForm="ContentReplace" style="margin: 133px;">
<label>Id</label>
<input type="text" name="id" value="" /><br>
<label>Amount</label>
<input type="text" name="amount" value="" /><br>
<label>Sum of Amount</label>
<input type="text" name="sum_amount" value="" /><br>
<input type="Submit" value="Search">
</form>
My model class is
#Entity
public class Amount {
#Id
Integer id;
Integer amount;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getAmount() {
return amount;
}
public void setAmount(Integer amount) {
this.amount = amount;
}
}
Now i know about JSR validation and Spring custom validation but they validate model data.You can see that i need a validation which query database and show error in form field.How can i do that?
It's perfectly reasonable to have injected a Service bean (that has an injected DAO bean) in your custom Validator to perform your lookup and based on that validation success or failure.

Spring , HIbernate need assistance

This is my index.jsp
<body>
<div class="container">
<div class="row">
<h1 class="text-center">Rupasinghe Trust Invesments</h1>
<div
class="col-lg-4 col-md-4 col-sm-8 col-xs-12 col-lg-offset-4 col-md-offset-4 col-sm-offset-2">
<div class="myForm">
<form:form class="form_signin" method="POST" commandName="user" action="login">
<%-- <form:input path="branch" type="text" class="form-control" name="branch"
placeholder="Branch Code" required="autofocus" /><br />
--%>
<form:input path="username"
type="text" class="form-control" name="username"
placeholder="Username" required="autofocus" /><br />
<form:input path="password"
type="password" class="form-control" name="password"
placeholder="Password" required="autofocus" /><br />
<input type="submit" value="Login" class="btn"/>
</form:form>
</div>
</div>
</div>
</div>
</body>
This is my LoginController.java
#Controller
public class LoginController {
#RequestMapping(value="/login" , method=RequestMethod.POST)
public String login(#ModelAttribute("user") User user , BindingResult result){
return "mainFrameAdminPanlel";
}
}
This is the bean User.java
#Entity
public class User {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int userId;
private String username;
private String password;
#ManyToOne
#JoinColumn(name="branchId")
private BranchEntity branch;
#OneToMany
private Set<UserAccess> userAccess;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public BranchEntity getBranch() {
return branch;
}
public void setBranch(BranchEntity branch) {
this.branch = branch;
}
public Set<UserAccess> getUserAccess() {
return userAccess;
}
public void setUserAccess(Set<UserAccess> userAccess) {
this.userAccess = userAccess;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
}
I am getting this error
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'user' available as request attribute
I am new to spring and still couldn't get what is wrong with this. Please help ! Thank you in advance
When you load the first page itself, I mean the page containing the form, you need to pass an instance of User. This exception is thrown since you have not passed instance of User that you are trying to use in the form. Kindly check.

How to populate a form:select and select a default value?

I have an edit user form which has textfields(username, lastname..) and a select of countries. I'm having problems with this select because i don't know the better way to populate it. I've tried populating with jquery with success but i cannot select a default value through commandName.
<form:form method="POST" commandName="user" action="registerUser.html">
<form:errors path="*" cssClass="errorblock" element="div" />
<spring:message code="app.user.username"/><form:input path="username" /><form:errors path="username" cssClass="error" /><br/>
<spring:message code="app.user.firstname"/> <form:input type="text" path="firstName" /> <form:errors path="firstName" cssClass="error"/><br/>
<spring:message code="app.user.password"/> <form:input type="password" path="password" /><form:errors path="password" cssClass="error"/><br/>
<spring:message code="app.user.repassword"/> <form:input type="password" path="confirmPassword" /><form:errors path="confirmPassword" cssClass="error"/><br/>
<spring:message code="app.user.email"/> <form:input type="text" path="email" /><form:errors path="email" cssClass="error"/><br/>
<spring:message code="app.user.country"/> <form:select path="isoCode" items="${countryList}"/><form:errors path="isoCode" cssClass="error"/><br/>
<input type="submit" value="Enviar" />
</form:form>
I've take a look to this tutorial, so i've tried with a map but i don't know how to return the data to be accesible in the jsp because in the tutorial uses a SimpleFormController but i wouldn't like to code a SimpleFormController for each form. This is my controller to return the view of the form and i have another to catch the submit.
#RequestMapping(method=RequestMethod.GET, value="/editUserForm")
public String recordUserRequestHandler(ModelMap model) throws Exception {
model.addAttribute("user", new User());
Map<String, Map<String, String>> referenceData = new HashMap<String, Map<String, String>>();
Map<String, String> country = new LinkedHashMap<String, String>();
country.put("US", "United Stated");
country.put("CHINA", "China");
country.put("SG", "Singapore");
country.put("MY", "Malaysia");
referenceData.put("countryList", country);
return "EditUserForm";
}
is it possible to pass the referenceData to the jsp to be accessed by the form:select?
<spring:message code="app.user.country"/> <form:select path="isoCode" items="${countryList}"/><form:errors path="isoCode" cssClass="error"/><br/>
Also you don't need to use hashmap for selects. Personally I use simple List with beans which holds my select options.
public class ListOption {
private String id;
private String name;
public ListOption(String id, String name) {
this.id = id;
this.name = name;
}
public ListOption() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
in your controller
List<ListOption> selectOptions = new List<ListOption>();
// add Your options
selectOptions.add(new ListOption("id","value");
then put isoCode object into your model with desired (selected) value then spring will manage to mark the value as selected.
in your jsp
<form:select path="isoCode" items="${countryList}" itemValue="id" itemLabel="name"/>

Resources