Fala Renan, tudo bem ?
O problema aí é o que Spring não tem ideia de como mapear cada String que vai a partir do select multiple sob o name permissoes quando do submit do formulário.
Pra resolver essa questão é um pouquinho mais difícil. Precisamos passar para o Spring um PropertyEditor para nossa propriedade permissoes
para que ele consiga entender que cada String recebida com essa chave deve virar um elemento de Permissoes dentro de uma lista.
Pra nossa sorte o Spring já tem implementações de PropertyEditor mais específicas para elementos de coleções =). Podemos usar, por exemplo, um CustomCollectionEditor.
Vamos ao exemplo:
Controller:
@Controller
@RequestMapping("/consultor")
public class ConsultorController {
@GetMapping("/form")
public ModelAndView form(Consultor consultor) {
List<Role> roles = Arrays.asList(new Role(1, "ROLE_1"),
new Role(2, "ROLE_2"),
new Role(3, "ROLE-3"));
ModelAndView modelAndView = new ModelAndView("index");
modelAndView.addObject("roles", roles);
return modelAndView;
}
@ResponseBody
@PostMapping
public String adiciona(Consultor consultor) {
List<Role> roles = consultor.getRoles();
roles.stream().forEach(role -> System.out.println(role));
return "ok";
}
Aqui temos um controller simples pra atender as requisicoes para o form e o submit do form.
Para esse exemplo temos as seguintes classes de modelo...
Consultor:
public class Consultor {
public Integer id;
public List<Role> roles = new ArrayList<>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
}
Role:
public class Role {
private Integer id;
private String nome;
public Role() {
}
public Role(int id, String nome) {
this.id = id;
this.nome = nome;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
@Override
public String toString() {
return "Role [id=" + id + ", nome=" + nome + "]";
}
}
View
...
<form:form action="${url }" method="post" commandName="consultor">
<form:select multiple="true" path="roles" items="${roles}" itemLabel="nome" itemValue="id" />
<input type="submit" />
</form:form>
...
(Aqui estou usando JSP + taglib form do Spring Mvc, mas pouco importa)
html resultante:
<form action="/contexto/consultor" method="post">
<select id="roles" name="roles" multiple="multiple">
<option value="1">ROLE_1</option>
<option value="2">ROLE_2</option>
<option value="3">ROLE-3</option>
</select>
<input type="hidden" name="_roles" value="1">
<input type="submit">
</form>
Com o código atual temos problemas as enviar (400). Mas se cadastrarmos para esse controller um PropertyEditor adequado o Spring consegue montar a lista com as roles.
Controller:
@Controller
@RequestMapping("/consultor")
public class ConsultorController {
@GetMapping("/form")
public ModelAndView form(Consultor consultor) {
...
}
@ResponseBody
@PostMapping
public String adiciona(Consultor consultor) {
...
}
@InitBinder
protected void initBinder(WebDataBinder binder) throws Exception {
CustomCollectionEditor rolesCollector = new CustomCollectionEditor(List.class) {
@Override
protected Object convertElement(Object element) {
if (element instanceof String) {
Integer id = Integer.parseInt((String) element);
Role role = new Role();
role.setId(id);
return role;
}
throw new RuntimeException("Spring says: Não sei o que fazer com esse elemento: " + element);
}
};
binder.registerCustomEditor(List.class, "roles", rolesCollector);
}
Agora o spring já tem o custom editor registrado para a propriedade recebida do form, e já sabe o que fazer com seus multiplos valores.
Teste:
Saída do console do método adiciona(..)
:
Espero ter ajudado. Abraço!