0

I'm new to Spring MVC and is making a simple todo web app. I'm getting the following error while binding data. I believe there is something with the jsp file with the Springmvc form where it messed up the binding process. I assume the bindingresult will return the form again but it does not for some reason.

org.apache.jasper.JasperException: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'todo' available as request attribute
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:549)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:465)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:168)
org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1257)
org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1037)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)

My updateToDo.jsp form

<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<head>
<title>update task</title>
<link href="webjars/bootstrap/4.5.0/css/bootstrap.min.css"
    rel="stylesheet">

</head>
<body>
    <div class="container">
        <H1>update your task!</H1>
    
        <form:form method="POST" commandName="todo">
            
            <fieldset class="form-group">
                <form:label path="description">Description:</form:label>
                <!-- required validates nulll -->
                <form:input path="description" type="text" class="form-control"
                    required="required" />
                <form:errors path="description" cssClass="text-warning" />
            </fieldset>

            <fieldset class="form-group">
                <form:label path="targetDate">Target Date</form:label>
                <form:input path="targetDate" type="Date" class="form-control"
                    required="required" />
                <form:errors path="targetDate" cssClass="text-warning" />

            </fieldset>
            <fieldset class="form-group">
                <form:radiobutton path="completion" value="true" />
                <form:radiobutton path="completion" value="false" />
                <form:errors path="targetDate" cssClass="text-warning" />
            </fieldset>

            <button type="submit" class="btn btn-success">Submit Update</button>
        </form:form>
        
    </div>
    <script src="webjars/jquery/3.5.1/jquery.min.js"></script>
    <script src="webjars/bootstrap/4.5.0/js/bootstrap.min.js"></script>

</body>
</html>

Controller

@Controller
public class ToDoController {

@Autowired
private ToDoService service;

@InitBinder
protected void initBinder(WebDataBinder binder) {
    SimpleDateFormat dateFormat = new SimpleDateFormat("mm/DD/yyyy");
    binder.registerCustomEditor(Date.class, new CustomDateEditor(
            dateFormat, false));
}

@RequestMapping(value = "/list-todo", method= RequestMethod.GET)
// HttpSession allows access to the session
public String showToDo(ModelMap model,  HttpSession httpSession) {
    String user = (String) httpSession.getAttribute("name");
    model.addAttribute("todos", service.retrieveTodos(user));
    return "list-todos";
}

// redirect to update form
@RequestMapping(value = "/update-todo", method= RequestMethod.GET)
public String getUpdateForm(ModelMap model, @RequestParam int id) {
    // To work with command bean
    model.addAttribute("todo", service.retrieveTodo(id));
    model.clear();
    return "updateToDo";
}

@RequestMapping(value = "/update-todo", method= RequestMethod.POST)
public String submitUpdate(ModelMap model, @Valid ToDo todo, BindingResult result) {
    if (result.hasErrors()) {
        return "redirect:/update-todo";
    }
    service.updateToDo(todo);
    model.clear();
    return "redirect:/list-todo";
}

// Will be executed first
@RequestMapping(value = "/add-todo", method= RequestMethod.GET)
public String showAddForm(ModelMap model) {
    model.addAttribute("todo", new ToDo());
    return "addToDo";
}


/*
 * Will be executed after form is submitted
 * @Valid ToDo - command bean from addToDo.jsp. 
 * @Valid to validate the information
 * @BindingResult showcases the result of the validation
 */
@RequestMapping(value = "/add-todo", method= RequestMethod.POST)
public String submitAddForm(ModelMap model , @Valid ToDo todo,  HttpSession httpSession, BindingResult result) {
    System.out.println("running" + result);
    // If there is validation error , return to addToDos page for user to fix the error
    if (result.hasErrors()) {
        return "redirect:/showAddForm";
    }
    String user = (String) httpSession.getAttribute("name");
    service.addTodo(user, todo.getDescription(), todo.getTargetDate(), false);      
    // Clears the url e.g. name?=jyj123
    model.clear();
    // return to the url which executes the showToDO
    return "redirect:/list-todo";
}

    // delete to do entry
 @RequestMapping(value = "/delete-todo", method= RequestMethod.GET) 
 public String deleteToDo(ModelMap model, @RequestParam int id) { 
     service.deleteTodo(id);
     model.clear();
     return "redirect:/list-todo"; }

}

2
  • Maybe i'm missing something, but i don't see where the endpoints are called from the .jsp. Commented Jul 4, 2020 at 3:58
  • @JWoodchuck getUpdateForm method in the controller gets the updateToDo.jsp Commented Jul 4, 2020 at 4:11

2 Answers 2

1

You are calling model.clear(), so removed todo attribute.

    public String getUpdateForm(final ModelMap model, @RequestParam final int id) {
        // To work with command bean
        model.addAttribute("todo", service.retrieveTodo(id));
        model.clear();
        return "updateToDo";
    }
Sign up to request clarification or add additional context in comments.

Comments

0

In layman's terms this is how Spring MVC works -

  • Create a bean (generally in GET handler) to which you want to bind your data. (This bean is referred to as command object)

  • Put the command object in model

  • Return a view name. (Spring will resolve the view and send the model to the view)

  • Bind data (user input) to the command object

  • Retrieve the command object with data in the controller (POST or other alike handlers)


Solution to Your Problem:

You are calling model.clear(); in your GET handler. So, in the view layer, the model is empty and no target bean (i.e. command object) is available to bind data to.

So remove the mode.clear(); call.

NOTE

One other common mistake is to use different names for the key of the command object in the model and in the value of commandName of <form:form/>.

i.e., If you put the command object in model as model.put("fooBar", someFooBar);, in view you need to do <form:form commandName="fooBar" .../>


Further Reading

1 Comment

Thank you for the answer. I was under the impression that model.clear only removes the variable in the URL

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.