title: Thymeleaf checkbox list passing values, but not displaying existing values
body: <p>I have an edit form for a Project object. Each project has a list of roles associated with them out of the complete list of all available roles. I need a checkbox list to select the roles. I implemented it like in this code sample I found thanks to StackOverflow, using a Formatter: <a href="https://github.com/jmiguelsamper/thymeleafexamples-selectmultiple" rel="nofollow noreferrer">https://github.com/jmiguelsamper/thymeleafexamples-selectmultiple</a></p>
  
  <p><strong>The issue</strong>: The form I created allows me to select the roles and save them successfully. But when I display an existing project object to edit it, the roles already associated with that project are not checked in the list. All the checkboxes are clear.</p>
  
  <p>The code sample above was with a String id. I use a Long id. I think that's the reason for the issue, but I don't know how to solve it. Should I drop the Formatter approach entirely? Is there a way to make this work?</p>
  
  <p>This is my code so far:</p>
  
  <p>Project class:</p>
  
  <pre><code>@Entity
  public class Project
  {
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      private Long id;
  
      private String name;
  
      @ManyToMany
      private List&lt;Role&gt; rolesNeeded;
  
      public Project()
      {
          rolesNeeded = new ArrayList&lt;&gt;();
      }
  
      //getters and setters omitted for brevity
  }
  </code></pre>
  
  <p>Role class:</p>
  
  <pre><code>@Entity
  public class Role
  {
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      private Long id;
  
      @NotNull
      @Column
      private String name;
  
      public Role() {}
  
      //getters and setters omitted for brevity
  }
  </code></pre>
  
  <p>Controller:</p>
  
  <pre><code>@Controller
  public class ProjectController
  {
      @Autowired
      private ProjectService projectService;
  
      @Autowired
      private RoleService roleService;
  
      @RequestMapping(value = "/projects/save", method = RequestMethod.POST)
      public String addProject(@Valid Project project)
      {
          projectService.save(project);
  
          return "redirect:/";
      }
  
      @RequestMapping("/projects/{id}/edit")
      public String editForm(@PathVariable Long id, Model model)
      {
          Project project = projectService.findById(id);
          model.addAttribute("project", project);
          model.addAttribute("allRoles", roleService.findAll());
  
          return "project/form";
      }
  }
  </code></pre>
  
  <p>The RoleFormatter:</p>
  
  <pre><code>@Component
  public class RoleFormatter implements Formatter&lt;Role&gt;
  {
      @Override
      public Role parse(String id, Locale locale) throws ParseException
      {
          Role role = new Role();
          role.setId(Long.parseLong(id));
          return role;
      }
  
      @Override
      public String print(Role role, Locale locale)
      {
          String id = role.getId() + "";
          return id;
      }
  }
  </code></pre>
  
  <p>And finally the Thymeleaf form:</p>
  
  <pre><code>&lt;!DOCTYPE html&gt;
  &lt;html lang="en" xmlns:th="http://www.thymeleaf.org"&gt;
  &lt;body&gt;
  &lt;section&gt;
      &lt;div class="container wrapper"&gt;
          &lt;form th:action="@{/projects/save}" method="post" th:object="${project}"&gt;
              &lt;input type="hidden" th:field="*{id}"/&gt;
              &lt;div&gt;
                  &lt;label for="project_name"&gt; Project Name:&lt;/label&gt;
                  &lt;input type="text" id="project_name" th:field="*{name}"/&gt;
              &lt;/div&gt;
              &lt;div&gt;
                  &lt;label&gt;Project Roles:&lt;/label&gt;
                  &lt;ul class="checkbox-list"&gt;
                      &lt;li th:each="role : ${allRoles}"&gt;
                          &lt;input type="checkbox" th:id="${{role}}" th:value="${{role}}" th:field="*{rolesNeeded}" /&gt;
                          &lt;span class="primary" th:text="${role.name}"&gt;&lt;/span&gt;
                      &lt;/li&gt;
                  &lt;/ul&gt;
              &lt;/div&gt;
              &lt;div class="actions"&gt;
                  &lt;button type="submit" value="Save" class="button"&gt;Save&lt;/button&gt;
                  &lt;a th:href="@{/}" class="button button-secondary"&gt;Cancel&lt;/a&gt;
              &lt;/div&gt;
          &lt;/form&gt;
      &lt;/div&gt;
  &lt;/section&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p><strong>UPDATE</strong></p>
  
  <p>As discussed in the comments: when I do not use the Formatter like above, I get a 400 Bad Request error. This is the header data of the POST request. In this case I tried selecting two roles (id 1 and 3 as you can see below)</p>
  
  <pre><code>Request URL:http://localhost:8080/projects/save 
  Request Method:POST 
  Status Code:400 Bad Request 
  Remote Address:[::1]:8080 
  Referrer Policy:no-referrer-when-downgrade 
  Response Headers 
  Connection:close 
  Content-Language:en-GB 
  Content-Length:350 
  Content-Type:text/html;charset=ISO-8859-1 
  Date:Tue, 31 Oct 2017 20:10:09 GMT 
  Server:Apache-Coyote/1.1 
  Request Headers 
  Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 
  Accept-Encoding:gzip, deflate, br Accept-Language:en-GB,en;q=0.9,en-US;q=0.8,fr;q=0.7 
  Cache-Control:max-age=0 
  Connection:keep-alive 
  Content-Length:161 
  Content-Type:application/x-www-form-urlencoded 
  Host:localhost:8080 
  Origin:http://localhost:8080 
  Referer:http://localhost:8080/projects/add 
  Upgrade-Insecure-Requests:1 
  User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
  AppleWebKit/537.36 (KHTML, like Gecko) 
  Chrome/62.0.3202.75 
  Safari/537.36 
  Form Data 
  id: 
  name:Implement recipe site 
  description:description 
  status:RUNNING 
  rolesNeeded:1
  _rolesNeeded:on
  _rolesNeeded:on 
  rolesNeeded:3
  _rolesNeeded:on
  _rolesNeeded:on
  </code></pre>