Invalid target for Validator - Spring MVC - java

I'm having problems with validating in Spring. I'm getting the following error after opening the form:
java.lang.IllegalStateException: Invalid target for Validator [com.example.validator.UserValidator#6ac0a8f4]: com.example.web.forms.UserDTO#4d3b2379
My Validator for the time being, wanted to check if anything works first:
#Component
public class UserValidator implements Validator {
#Autowired
ServiceUser serviceUser;
#Override
public boolean supports(Class<?> clazz) {
return User.class.equals(clazz);
}
#Override
public void validate(Object target, Errors errors) {
User user = (User) target;
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "NotEmpty.userForm.name");
}
}
Controller:
#Controller
public class UserController {
#Autowired
UserValidator userValidator;
#InitBinder
public void initBinder(WebDataBinder binder) {
CustomDateEditor editor = new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true, 10);
binder.registerCustomEditor(Date.class, editor);
binder.setValidator(userValidator);
// binder.addValidators(userValidator);
}
final static Logger logger = Logger.getLogger(UserController.class);
#Autowired
protected ServiceUserImpl service;
#RequestMapping("/lista")
public String showIndex(Model model) {
User contest = new User();
model.addAttribute("element", contest);
model.addAttribute("collection", service.findAll());
return "lista";
}
#RequestMapping("/dodaj")
public String showFormPublication(HttpServletRequest request, #ModelAttribute("userDto") #Valid UserDTO userDTO, BindingResult result) {
if (request.getMethod().equalsIgnoreCase("post") && !result.hasErrors()) {
if (result.hasErrors()) {
return "forms/contest";
} else {
User user = new User();
user.setId(userDTO.getId());
user.setName(userDTO.getName());
user.setSurname(userDTO.getSurname());
user.setDateOfBirth(userDTO.getDateOfBirth());
user.setIndexNumber(userDTO.getIndexNumber());
user.setEmail(userDTO.getEmail());
service.save(user);
return "redirect:/lista";
}
}
return "dodaj";
}
}
Form in .jsp:
<form:form action="dodaj" method="POST" modelAttribute="userDto">
<table border="1">
<tbody>
<tr>
<th>ImiÄ™</th>
<td>
<form:input type="text" path="name" />
<c:if test="${pageContext.request.method=='POST'}"><form:errors path="name" /></c:if>
</td>
</tr>
<tr>
<th>Nazwisko</th>
<td>
<form:input type="text" path="surname" />
<c:if test="${pageContext.request.method=='POST'}"><form:errors path="surname" /></c:if>
</td>
</tr>
<tr>
<th>DataUrodzenia</th>
<td>
<form:input type="date" path="dateOfBirth" />
<c:if test="${pageContext.request.method=='POST'}"><form:errors path="dateOfBirth" /></c:if>
</td>
</tr>
<tr>
<th>NumerIndeksu</th>
<td>
<form:input type="number" path="indexNumber" />
<c:if test="${pageContext.request.method=='POST'}"><form:errors path="indexNumber" /></c:if>
</td>
</tr>
<tr>
<th>Email</th>
<td>
<form:input type="text" path="email" />
<c:if test="${pageContext.request.method=='POST'}"><form:errors path="email" /></c:if>
</td>
</tr>
<tr>
<td colspan="2" align="right"><input type="submit" value="Dodaj!" /></td>
</tr>
</tbody>
</table>
</form:form>
I tried adding ("userDto") next to #InitBinder, it didn't help unfortunately. Haven't found much more in terms of applicable solutions. If there's anything else I should post here let me know. I can also provide a link to repository should anyone be eager enough to try to run it.

I think you need to change the supports method in UserValidator to UserDTO class:
public boolean supports(Class<?> clazz) {
return UserDTO.class.equals(clazz);
}

Related

How to have add and remove buttons in html form handle by spring 5 controller?

I am using Spring 5 and Hibernate 5.
I have got form like below in jsp file:
<form:form action="addUser" method="post" modelAttribute="user">
<table>
<tr>
<td>Name</td>
<td>
<form:input path="name" /> <br />
<form:errors path="name" cssClass="error" />
</td>
</tr>
<tr>
<td>Email</td>
<td>
<form:input path="email" /> <br />
<form:errors path="email" cssClass="error" />
</td>
</tr>
<tr>
<td colspan="1"><button type="submit">Submit</button></td>
<td colspan="1"><button type="???delete???">Remove</button></td>
</tr>
</table>
</form:form>
And UserController.java like below:
#Controller
public class UserController {
#Autowired
private UserService userService;
#GetMapping("/")
public String userForm(Locale locale, Model model) {
model.addAttribute("users", userService.list());
return "editUsers";
}
#ModelAttribute("user")
public User formBackingObject() {
return new User();
}
#PostMapping("/addUser")
public String saveUser(#ModelAttribute("user") #Valid User user, BindingResult result, Model model) {
if (result.hasErrors()) {
model.addAttribute("users", userService.list());
return "editUsers";
}
userService.save(user);
return "redirect:/";
}
}
Right now I have got a submit button which allow me to save name and email of the user.
I would like to add button REMOVE which would also relay on the same form but will instead of adding new user will be removing existing user.
Could you tell how can I do it?
Maybe the first option is to add some attribute like action, but then I need to handle it in controller and I don't know how?
Thank you.
It can be done by changing the form action dynamically based on the button click using some javascript.
<script>
$('#addBtn').click(function(){
$("#userForm").submit();
});
$('#removeBtn').click(function(){
$('#userForm').attr('action', '<your remove action>');
$("#userForm").submit();
});
<script>
<form:form action="addUser" method="post" modelAttribute="user" id="userForm">
...
<td colspan="1"><button type="button" id='addBtn'>Submit</button></td>
<td colspan="1"><button type="button" id='removeBtn'>Remove</button></td>
...
</form:form>

After submitting a form go back to previous page (Spring/Hibernate)

I have a restaurant edit page located "/restaurant/edit/{id}". From that page I can (among other things) add tables to the restaurant by pressing an "Add tables" button. That button takes me to another page located "/restaurant/edit/{id}/table". The question is, after I have added the table - how do I get back to the previous page by pressing a button? Right now my contoller is returning "editRestaurant.jsp" which is the right value, but I don't know how to pass that same restaurant id as well. I hope you understand what I mean.
My RestaurantTableController.java:
#Controller
public class RestaurantTableController {
#Autowired
private RestaurantService restaurantService;
#Autowired
private RestaurantTableService restaurantTableService;
#RequestMapping(value="restaurant/{id}/table", method = RequestMethod.GET)
public String addRestaurantTable(Model model, #PathVariable Long id) {
model.addAttribute("table", new RestaurantTable());
return "newTable";
}
#RequestMapping(value = "restaurant/{id}/table", method = RequestMethod.POST)
public String addRestaurantTableAction(#PathVariable Long id, #ModelAttribute ("table") RestaurantTable table, BindingResult result) {
RestaurantTableFormValidator restaurantTableFormValidator = new RestaurantTableFormValidator();
restaurantTableFormValidator.validate(table, result);
if (result.hasErrors()) {
return "newTable";
}
restaurantService.mergeRestaurant(id, table);
return "editRestaurant";
}
}
My "newTable.jsp":
<body>
<jsp:include page="../fragments/menu.jsp"/>
<div id="body">
<section class="content-wrapper main-content clear-fix">
<h2>Add New Table</h2>
<form:form method="POST" modelAttribute="table">
<table>
<tr>
<td>Table size:</td>
<td><form:input path="tableSize" /></td>
<td><form:errors path="tableSize" cssClass="error"/></td>
</tr>
<tr>
<td>Table number:</td>
<td><form:input path="tableNumber" /></td>
<td><form:errors path="tableNumber" cssClass="error"/></td>
</tr>
<tr>
<td colspan="3"><input type="submit" onclick="goback()"/>
</td>
</tr>
</table>
</form:form>
</section>
</div>
<jsp:include page="../fragments/footer.jsp"/>
</body>
Relevant methods in RestaurantController.java:
#RequestMapping(value = "restaurant/edit/{id}", method = RequestMethod.GET)
public String editRestaurant(#PathVariable Long id, Model model) {
Restaurant restaurant = restaurantService.getRestaurant(id);
model.addAttribute("restaurant", restaurant);
return "editRestaurant";
}
#RequestMapping(value = "restaurant/edit/{id}", method = RequestMethod.POST, params="submit")
public String editRestaurant(#ModelAttribute ("restaurant") Restaurant restaurant, BindingResult result) {
RestaurantFormValidator restaurantFormValidator = new RestaurantFormValidator();
restaurantFormValidator.validate(restaurant, result);
if (result.hasErrors()) {
return "editRestaurant";
}
restaurantService.updateRestaurant(restaurant);
return "redirect:/bookings";
}
"editRestaurant.jsp":
<div id="body">
<section class="content-wrapper main-content clear-fix">
<h2>Edit</h2>
<form:form method="POST" modelAttribute="restaurant" >
<table>
<tr>
<td>Restaurant:</td>
<td><form:input path="restaurantName" /></td>
<td><form:errors path="restaurantName" cssClass="error"/></td>
</tr>
<tr>
<td>Address:</td>
<td><form:input path="address" /></td>
<td><form:errors path="address" cssClass="error"/></td>
</tr>
<tr>
<td colspan="3"><input type="submit" value="Submit" name="submit"/>
</td>
</tr>
<tr>
<c:forEach items="${restaurant.table}" var="item">
<td>${item.toString()}</td>
</c:forEach>
</tr>
<tr>
<td>Add Table</td>
</tr>
</table>
</form:form>
<div>
Back to List
</div>
</section>
</div>
After successful POST you should do a redirect.
Something like this:
return "redirect:/restaurant/edit/" + restaurant.getId();
or
return new RedirectView("/restaurant/edit/" + restaurant.getId(), false);
There is a different method you can use to return the model that will include the parameter. I believe this may solve your problem.
#RequestMapping(value = "restaurant/edit/{id}", method = RequestMethod.GET)
public String editRestaurant(#PathVariable Long id, Model model) {
Restaurant restaurant = restaurantService.getRestaurant(id);
return new ModelAndView("editRestaurant", "restaurant", restaurant);
}

Spring JSP passing variables

I want to handle simple form. Here's form from my signUp.jsp, where from I receive my data
<form:form method="POST" commandName="user-entity" action="process.html">
<table>
<tr>
<td><form:label path="userName">Name:</form:label></td>
<td><form:input path="userName" /></td>
</tr>
<tr>
<td><form:label path="label">Age:</form:label></td>
<td><form:label path="label"/></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Submit"/>
</td>
<td></td>
<td></td>
</tr>
</table>
</form:form>
And part of my result.jsp
<p>User's name is ${user.userName}. The age is ${user.age}.</p>
And UserController.java
#Controller
public class UserController {
#RequestMapping(value = "/signUp")
public ModelAndView signUpPage() {
return new ModelAndView("signUp", "user-entity", new User());
}
#RequestMapping(value = "/process")
public ModelAndView processUser(#ModelAttribute User user) {
ModelAndView model = new ModelAndView();
model.setViewName("result");
model.addObject("user", user);
return model;
}
}
As the result I get
User's name is ${user.userName}. The age is ${user.password}.
and i have no idea why. Where might be the problem?
Missing
<%# page isELIgnored="false"%> in result.jsp
Solution brought from here

Form validation with form:options

Form:Options working pretty well, but if I submit wrong data in Form, form:options in newContact.jsp shows the first element of departmentList as selected.
ContactController:
#RequestMapping(value="/saveContact", method=RequestMethod.GET)
public ModelAndView newuserForm(){
ModelAndView mav = new ModelAndView("newContact");
// Contact contact = new Contact();
// Department department = new Department();
User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String name = user.getUsername();
mav.addObject("username", name);
mav.addObject("newContact", new Contact());
// mav.addObject("department", department);
mav.addObject("departmentList", departmentService.listDepartment());
//mav.getModelMap().put("newContact", contact);
return mav;
}
#RequestMapping(value="/saveContact", method=RequestMethod.POST)
public String create(#ModelAttribute("newContact")Contact contact, BindingResult result, SessionStatus status,Map<String, Object> map)
{
User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String name = user.getUsername();
map.put("departmentList", departmentService.listDepartment());
map.put("username", name);
contactFormvalidator.validate(contact, result);
if (result.hasErrors())
{
return "newContact";
}
contactService.addContact(contact);
status.setComplete();
//return "redirect:/showContacts.do";
return "newContactSuccess";
}
newContact.jsp:
<%#include file="header.jsp"%>
<div id="menu">
<div id="subMenu"></div>
</div>
<div id="main">
<h2>Contact Manager</h2>
<form:form method="post" action="saveContact.do" commandName="newContact" >
<table>
<tr>
<td><form:label path="firstname">
<spring:message code="label.firstname" />
</form:label></td>
<td><form:input path="firstname" /></td>
<td><form:errors path="firstname" cssStyle="color:red"></form:errors> </td>
</tr>
<tr>
<td><form:label path="lastname">
<spring:message code="label.lastname" />
</form:label></td>
<td><form:input path="lastname" /></td>
<td><form:errors path="lastname" cssStyle="color:red"></form:errors> </td>
</tr>
<tr>
<td><form:label path="email">
<spring:message code="label.email" />
</form:label></td>
<td><form:input path="email" /></td>
<td><form:errors path="email" cssStyle="color:red"></form:errors> </td>
</tr>
<tr>
<td><form:label path="telephone">
<spring:message code="label.telephone" />
</form:label></td>
<td><form:input path="telephone" /></td>
<td><form:errors path="telephone" cssStyle="color:red"></form:errors> </td>
</tr>
<tr>
<td><form:label path="department">
<spring:message code="label.department" />
</form:label></td>
<td><form:select path="department" >
<form:option label="**SELECT**" value="0"></form:option>
<form:options items="${departmentList}" itemValue="id" itemLabel="name"></form:options>
</form:select> </td>
<td><form:errors path="department" cssStyle="color:red"></form:errors> </td>
</tr>
<tr>
<td colspan="2"><input type="submit"
value="<spring:message code="label.addcontact"/>" /></td>
</tr>
</table>
</form:form>
</div>
<%# include file="footer.jsp"%>
ContactFormValidator:
package pl.ivmx.contact.validator;
import java.util.regex.*;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import pl.ivmx.contact.form.Contact;;
//#Component("contactFormValidator")
public class ContactFormValidator implements Validator{
#Override
public boolean supports(Class clazz) {
return Contact.class.isAssignableFrom(clazz);
}
#SuppressWarnings("unchecked")
#Override
public void validate(Object obj, Errors errors) {
Contact contact = (Contact) obj;
Pattern p = Pattern.compile("[a-zA-Z]*[0-9]*#[a-zA-Z]*.[a-zA-Z]*");
Matcher m = p.matcher(contact.getEmail());
boolean b = m.matches();
if (b != true) {
errors.rejectValue("email", "error.is.not.valid",
"Email does not Valid ");
}
if (contact.getFirstname() == null || contact.getFirstname().length() < 3) {
errors.rejectValue("firstname", "error.empty.field",
"Please Enter First Name");
}
if (contact.getLastname() == null || contact.getLastname().length() < 4) {
errors.rejectValue("lastname", "error.empty.field",
"Please Enter Last Name");
}
if (contact.getTelephone() == 0 || String.valueOf(contact.getTelephone()).trim().length() < 2 ||
String.valueOf(contact.getTelephone()).trim().length() > 9) {
errors.rejectValue("telephone", "error.empty.field",
"Please Enter Telephone");
}
if (contact.getDepartment() == null) {
errors.rejectValue("department", "error.empty.field",
"Please select department");
}
}
}
Instead of returning String in your submit method return ModelAndView ...
#RequestMapping(value="/saveContact", method=RequestMethod.POST)
public ModelAndView create(#ModelAttribute("newContact")Contact contact, BindingResult result, SessionStatus status,ModelMap map)
{
User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String name = user.getUsername();
map.addAttribute("departmentList", departmentService.listDepartment());
map.addAttribute("username", name);
contactFormvalidator.validate(contact, result);
if (result.hasErrors())
{
return new ModelAndView("newContact",map);
}
contactService.addContact(contact);
status.setComplete();
//return new ModelAndView("redirect:/showContacts.do");
return new ModelAndView("newContactSuccess");
}

Neither BindingResult nor plain target object for bean name 'index' available as request attribute

I have a problem when trying to access the controller.
Here is my controller:
#Controller
#RequestMapping("/index.htm")
public class LoginController {
#Autowired
private UserService userService;
#RequestMapping(method = RequestMethod.GET)
public String showForm(Map model) {
model.put("index", new LoginForm());
return "index";
}
#RequestMapping(method = RequestMethod.POST)
public String processForm(LoginForm loginForm, BindingResult result,
Map model) {
if (result.hasErrors()) {
HashMap<String, String> errors = new HashMap<String, String>();
for (FieldError error : result.getFieldErrors()) {
errors.put(error.getField(), error.getDefaultMessage());
}
model.put("errors", errors);
return "index";
}
List<User> users = userService.getUsers();
loginForm = (LoginForm) model.get("loginForm");
for (User user : users) {
if (!loginForm.getEmail().equals(user.getEmail()) || !loginForm.getPassword().equals(user.getPassword())) {
return "index";
}
}
model.put("index", loginForm);
return "loginsuccess";
}
}
Here is my form:
<form:form action="index.htm" commandName="index">
<table border="0" cellspacing="12">
<tr>
<td>
<spring:message code="application.loginForm.email"/>
</td>
<td>
<form:input path="email"/>
</td>
<td class="error">
<form:errors path="email"/>
</td>
</tr>
<tr>
<td>
<spring:message code="application.loginForm.password"/>
</td>
<td>
<form:password path="password"/>
</td>
<td class="error">
<form:errors path="password"/>
</td>
</tr>
<tr>
<td>
<input type="submit" value="Submit"/>
</td>
</tr>
</table>
</form:form>
On form submit I am getting this exception:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'index' available as request attribute.
What am I doing wrong here?
It's because you're only doing this bit down at the bottom
model.put("index", loginForm);
If you return from the validation error, or from a success, there is no backing object in the model map named "index" so your form tag that has commandName="index" pitches a fit.
A common solution is to simply do this
#ModelAttribute("index")
public LoginForm getLoginForm() {
return new LoginForm();
}
Then there will always be one present, and you can take adding it out of the GET method.

Categories