I'm using JSF 2.0, PrimeFaces and OmniFaces.
I have 2 dialogs with <h:selectManyCheckbox>
. The first dialog creates a new Course
:
The Disciplina
s are presented as:
<h:selectManyCheckbox id="disciplinas"
value="#{cursoMBean.listaDisciplinasDoCurso}"
converter="omnifaces.SelectItemsConverter">
<f:selectItems value="#{cursoMBean.listaTodasDisciplinas}"
var="disciplina" itemValue="#{disciplina}"
itemLabel="#{disciplina.nome}" />
</h:selectManyCheckbox>
This works fine. When I select some disciplines and submit the form, then the new Course
with the selected Discipline
s is properly inserted in the DB.
However, when I try to retrieve an existing Course
from the DB, the saved Discipline
s are not preselected.
The code is the same:
<h:selectManyCheckbox id="disciplinas"
value="#{cursoMBean.listaDisciplinasDoCurso}"
converter="omnifaces.SelectItemsConverter">
<f:selectItems value="#{cursoMBean.listaTodasDisciplinas}"
var="disciplina" itemValue="#{disciplina}"
itemLabel="#{disciplina.nome}" />
</h:selectManyCheckbox>
Here's the backing bean:
private ArrayList<Disciplina> listaTodasDisciplinas;
private ArrayList<Disciplina> listaDisciplinasDoCurso;
public CursoMBean() {
if (listaTodasDisciplinas == null) {
listaTodasDisciplinas = controleDisciplina.consulta();
}
if (listaDisciplinasDoCurso == null) {
listaDisciplinasDoCurso = new ArrayList<Disciplina>();
}
}
// When user selects one Course to edit, this method is called:
public void setSelecionado(Curso selecionado) {
this.selecionado = selecionado;
if (selecionado != null) {
listaTodasDisciplinas = controleDisciplina.consulta();
listaDisciplinasDoCurso = controleCurso.listaDisciplinasAssociadas(selecionado);
}
}
Here's the Disciplina
entity:
public class Disciplina {
private int id;
private String nome;
public Disciplina() {
}
public Disciplina(int id, String nome) {
this.id = id;
this.nome = nome;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
if (!(nome.isEmpty() || nome == " " || nome == " ")){
this.nome = nome;
}
}
}
How is this caused and how can I solve it?
By default, the
SelectItemsConverter
relies ontoString()
of the entity to match the selected items. Your entity however doesn't have atoString()
implemented and is thus relying on defaultfqn@hashcode
result which is not the same when two physically differentDisciplina
instances are created even though they have the same value.You've basically 2 options, also hinted in
SelectItemsConverter
showcase and javadoc:Implement a
toString
method that uniquely identifies the entity and which makes sense as an identifier. For example,(note that this
toString()
is designed such that you can easily keep it in an abstract base class of all your entities, so that you don't need to copypaste the same over all your entities)Or, if implementing such a
toString()
is not an option for some reason (e.g. relying on generated classes which can't be modified afterwards (neither the generator template)), then extend the converter as follows:(note: you should really be using
Integer
instead ofint
as ID, theint
cannot benull
which is the correct way to represent a brand new and unpersisted entity)And use it as follows