Spring Framework <form:errors/> tag not showing errors
Asked Answered
I

1

5

I know there are many similar questions here, but none of them solved my problem.

I'm using Spring 4.0.3 and Hibernate Validator 5.1.0. The problem occurs when I try to omit the path attribute of the <form:errors/> tag, so:

<form:errors path="contato.nome" /> works
<form:errors path="*" /> works
<form:errors /> doesn't work

I don't know why it happens. Spring javadocs (org.springframework.web.servlet.tags.form.ErrorsTag) says it should work like that:

Field only - set path to the field name (or path)
Object errors only - omit path
All errors - set path to *

Can you help me, please?

The interested code is in the 'edicao.jsp' and in the method 'confirmarEdicao' of the ContatoController.java. Sorry if my english is bad.


ContatoController.java

@Controller
@RequestMapping("/contatos")
public class ContatoController {

    @Autowired
    private ContatoService contatoService;

    @Autowired 
    private MessageSource messageSource;

    @RequestMapping(value = "/confirmarEdicao", method = RequestMethod.POST)
    public String confirmarEdicao(@Valid Contato contato, BindingResult bindingResult) {

        if(bindingResult.hasErrors()) {
            return "contatos/edicao";
        }

        contatoService.save(contato);
        return "redirect:/contatos";
    }

    @RequestMapping(method = RequestMethod.GET)
    public ModelAndView form(HttpServletRequest request) {
        String message = messageSource.getMessage("teste", null, new Locale("pt", "BR"));
        System.out.println(message);
        return new ModelAndView("contatos/listagem")
            .addObject("contatos", contatoService.list());
    }

    @RequestMapping("/remover/{id}")
    public String remover(Contato contato) {
        contatoService.delete(contato);
        return "redirect:/contatos";
    }

    @RequestMapping("/editar/{id}")
    public ModelAndView formEdicao(Contato contato) {
        contato = contatoService.find(contato.getId());
        return new ModelAndView("contatos/edicao")
            .addObject(contato);
    }


    @RequestMapping(value = "/cadastrar")
    public String formCadastro() {
        return "contatos/cadastro";
    }

    @RequestMapping(value = "/confirmarCadastro", method = RequestMethod.POST)
    public String confirmarCadastro(@Valid Contato contato, BindingResult bindingResult, 
            RedirectAttributes redirectAttributes) {        

        if (bindingResult.hasFieldErrors()) {
            return "contatos/cadastro";
        }

        contatoService.save(contato);
        redirectAttributes.addFlashAttribute("mensagem", "Contato cadastrado com sucesso.");
        return "redirect:/contatos";
    }   

    @ResponseBody
    @RequestMapping(value = "/pesquisar/{nome}", method = RequestMethod.GET, 
        produces="application/json")
    public List<Contato> pesquisar(@PathVariable String nome) {
        return contatoService.findByName(nome);
    }

}

edicao.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Editar contato</title>
</head>
<body>

<c:set var="context">${pageContext.request.contextPath}</c:set>
<script type="text/javascript">var context = "${context}";</script>
<script src="${context}/resources/js/jquery-2.1.0.min.js"></script>
<script src="${context}/resources/js/contatos/edicao.js"></script>

<form:form commandName="contato" action="${context}/contatos/confirmarEdicao" method="post">
<form:errors/>
    <table>
        <form:hidden path="id"/>
        <tr>
            <td>Nome:</td> 
            <td><form:input path="nome" /></td>
        </tr>
        <tr>
            <td>Telefone:</td>
            <td><form:input path="telefone"/></td>
        </tr>
        <tr>
            <td><input type="button" value="Voltar" id="btn_voltar"/><input type="submit" value="Salvar"/></td>         
        </tr>
    </table>
</form:form>

</body>
</html>

Contato.java

package com.handson.model;

import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.NotEmpty;

public class Contato {

    private Long id;

    @Size(min = 3, message = "Nome deve ter no mínimo 3 caracteres")
    @NotEmpty(message = "O nome deve ser preenchido")
    private String nome;

    private String telefone;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public String getTelefone() {
        return telefone;
    }

    public void setTelefone(String telefone) {
        this.telefone = telefone;
    }

    public Contato withId(Long id) {
        setId(id);
        return this;
    }

    public Contato withTelefone(String telefone) {
        setTelefone(telefone);
        return this;
    }

    public Contato withNome(String nome) {
        setNome(nome);
        return this;
    }

    @Override
    public String toString() {
        return "Contato [id=" + id + ", nome=" + nome + ", telefone="
                + telefone + "]";
    }

}
Illusage answered 26/4, 2014 at 21:50 Comment(6)
I think that omit path mean that you have not to write that attribute at all. Remove the path attribute from your tagLongmire
@mserioli, that was a copy and paste error, please see the edited question.Illusage
So what is exactly the question? Object errors are errors whose path is equal to the model attribute name. Field errors are not object level errors.Runner
@PavelHoral the question is why the tag <form:errors/> in edicao.jsp is not showing the errors. As I understand, it should show the errors of the Contato object (and any others objects used in the method confirmarEdicao of the controller).Illusage
@user3576535 Nope... every error is associated with a property path (e.g. contato.id => typeMismatch). This tag without its path attribute shows only errors for the current nested path, which is contanto in your case. So no child field (e.g. contanto.nome) error will be displayed. This is what the JavaDoc is telling you.Runner
@PavelHoral so I think I misunderstood the term "Object errors only". I thought it would display all errors of all fields from this object. Thank you for clarifying. If you post this as an answer, I can accept it.Illusage
R
14

There are some keywords which should be defined:

  • path - EL-like path to an object or to a field of an object (e.g. foo, foo.bar or foo.bar.baz)
  • nested path - current path context stored as nestedPath request attribute (new paths are relative to this path)
  • object error - error connected with object itself (e.g. path is equal to foo)
  • field error - error connected with object field (e.g. path is foo.bar)

The tag <form:form commandName="foo"> defines nested path as nestedPath=foo. When you write <form:errors path="bar"> it tries to find errors defined for path foo.bar.

Lets say that you have errors connected with foo (object error), foo.bar and foo.bar.baz (nested field error). What this means:

  • if you enter <form:errors>, only errors bound to foo path are displayed => 1 message
  • if you enter <form:errors path="bar">, only errors bound to foo.bar path are displayed => 1 message
  • if you enter <form:errors path="*">, errors bound to foo and its child paths are displayed => 3 messages
  • if you enter <form:errors path="bar.*">, only child errors for foo.bar are diplayed => 1 message
  • if you enter <form:errors path="bar*">, errors bound to foo.bar and its child paths are diplayed => 2 messages

Checking on Errors class JavaDoc might give you additional insight.

Runner answered 28/4, 2014 at 11:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.