Spring WebMVC's tag library: form:checkboxes works as expected while an iteration over form:checkbox does not

StackOverflow https://stackoverflow.com/questions/22724747

  •  23-06-2023
  •  | 
  •  

Question

Introduction

When creating a form for an @Entity with a related list, I ran into a strange behaviour. <form:checkboxes/>and an iteration over a list generating several <form:checkbox/> behave differently where they should not, at last not from my point of view.

The code

I have removed everything which seemed unnecessary to me, but feel free to ask if any code is missing.

Models

I have a more ore less simple (or anemic as some might say) models of roles and rights.

The entity for Role:

@Entity
public class Role implements Serializable{

/* Setters and Getters and some annotations omitted for readability
 * Some annotations too. Unittests for the relations have no error so far.
 */

  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private Long id;

  @Version
  private Date lastModified;

  @ManyToMany(cascade={CascadeType.PERSIST,CascadeType.MERGE},fetch=FetchType.EAGER)
  private List<Right> rights = new ArrayList<Right>();
}

And for Right:

@Entity
public class Right implements GrantedAuthority,Serializable{

  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private Long id;

  @Version
  @Temporal(TemporalType.TIMESTAMP)
  private Date lastModified;

  @ManyToMany(mappedBy="rights")
  private List<Role> roles;

}

The form

Now obviously I want to add rights to my roles. This is a dynamic process in my app, so there is a form for it. Please see the comments in code for further details.

<form:form commandName="role">
    <p>
        <form:label path="name">Role Name</form:label><br/>
        <form:input path="name" cssClass="form-control"/>
    </p>
    <p>
        <form:label path="description">Description of role</form:label><br/>
        <form:textarea path="description" rows="3" class="form-control"></form:textarea>
    </p>
    <p>
        <%-- Now for whatever reason this (form:checkboxes) works as expected: --%>
        <%-- * Transfers correct values to the controller --%>
        <%-- * Is correctly checked and unchecked when the controller returns the page --%> 
        <form:checkboxes items="${allRights}" path="rights" itemLabel="name" itemValue="id" delimiter=" - "/>

        <%-- This does not work: --%>
        <%-- * The values are sent to the controller --%>
        <%-- * My CustomCollectionsEditor resolves the to the according rights --%>
        <%-- * Once the method returns, the values simply dissapear --%>
        <%--    <c:forEach items="${allRights}" var="right"> --%>
        <%--        <form:checkbox path="rights"  value="${right.id}" />${right.name} --%>
        <%--    </c:forEach> --%>
    </p>
    <p><button type="submit">Create new role</button></p>

</form:form>

The controller

My @Controller does nothing more than to create the form and send it back at the moment:

/* Makes allRights available in every page */
/* rightService.getRights() WAS an eternally cached method (memory only) 
 * but I deactivated caching when I ran into these problems
 */ 
@ModelAttribute("allRights")
public List<Right> populateRights() {
  _logger.debug("allRights:{}",rightService.getRights());
  return rightService.getRights();
}

@RequestMapping(value = "/add", method = RequestMethod.GET)
public ModelAndView addRoleView(ModelMap model) {
  model.addAttribute("role", new Role());
  return new ModelAndView("admin/roles/add", model);
}

@RequestMapping(value = "/add", method = RequestMethod.POST)
public ModelAndView addRole(@ModelAttribute("role") Role role,
            BindingResult result , ModelMap model) {

  /* Logs the selected rights and does so for both methods */
  _logger.debug("Role's Rights:{}",role.getRights());

  return new ModelAndView("admin/roles/add",model);
}
/* @InitBinder omitted for readability, as it is obviously working since both
 * ways actually send the data to the Controller method.
 */

Questions

  1. Is the behavior of the form what could be expected in conjunction with my code?
  2. If yes: Why and what am I missing here?
  3. If no: Do you see a work around other than processing the form entirely by hand?

Thanks...

...for taking the time to read this question and for your answer!

Was it helpful?

Solution

Actually, it was my fault (as to be expected).

To be able to use related fields in this way, one either needs to implement an according @InitBinder or a Formatter.

See the according thread in Thymeleaf's user forum for details.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top