I have tried to set up two selectOneMenus where the first selects an object, and in the second, one of five object parameters can be selected. For this, I have built a custom converter, and "id" should be passed from the first selectOneMenu to uniqely identify the object for the second menu. On page load, the getAsString
method is called and iterated through all items of the first menu. On selecting an item, getAsObject
is called, and the correct id
is used and the correct Question
is returned. But: the second menu is not populated at all. What did I miss? Help appreciated, I'm still learning this.
Here is the first selectOneMenu:
<h:selectOneMenu converter="answerDeliverer">
<f:selectItems value="#{questionBean.list}" var="question" itemValue="#{question}" itemLabel="#{question.text}"/>
<f:ajax event="change" render="answers"></f:ajax>
</h:selectOneMenu>
And the second:
<h:selectOneMenu id="answers">
<f:selectItem itemValue="1" itemLabel="#{question.a1}"/>
<f:selectItem itemValue="2" itemLabel="#{question.a2}"/>
<f:selectItem itemValue="3" itemLabel="#{question.a3}"/>
<f:selectItem itemValue="4" itemLabel="#{question.a4}"/>
<f:selectItem itemValue="5" itemLabel="#{question.a5}"/>
</h:selectOneMenu>
And the converter:
@ManagedBean (name = "answerDeliverer")
@RequestScoped
public class answerDeliverer implements Converter {
@EJB
private QuestionDAO questionDAO;
@Override
public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String s) {
return questionDAO.get(Integer.parseInt(s));
}
@Override
public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object o) {
if (o instanceof Question) {
return ((Question) o).getId();
} else if (o instanceof String) {
return ((String) o);
} else throw new ConverterException(new FacesMessage(o + " is not a valid Question or id"));
//just so I can try either question or question.id as itemValues
}
}
The error log is empty, only on startup I get several warnings of this type:
Unknow type constant pool 18 at position 7
Nov 03, 2015 1:17:10 PM com.sun.faces.config.JavaClassScanningAnnotationScanner$ConstantPoolInfo containsAnnotation
After hours and hours of debugging, I'm stuck now. I can conclude the following:
- The
answerDeliverer
seems to work. On selection,getAsObject
fetches the correctquestion
from the DB - XHR is registered in browser debug mode on every selection with a "200 OK" server answer
- There is no other error in the log
- I seem to have something wrong with bringing the
question
into the scope of the second selectOneMenu.Question
is not aManagedBean
, and in myQuestionBean
,private Question question = new Question()
, so, could it be that no matter what I do in the first selectOneMenu, the second always generates a new instance and doesn't care about what I did before? And thus erases anyquestion
I had before? How could I avoid that?
I'm using Mojarra-2.2.1 on Tomcat 8. Also tried to go with OmniFaces, but got stuck in an infinite loop of debugging the setup there before giving up on that.
I'll add my Question
POJO and the Bean if that helps any.
public class Question implements Serializable {
private String text;
private String a1 = Constants.defaulta1;
private String a2 = Constants.defaulta2;
private String a3 = Constants.defaulta3;
private String a4 = Constants.defaulta4;
private String a5 = Constants.defaulta5;
private String id;
private String nodeid;
//getters and setters
@Override
public boolean equals(Object other) {
return (other != null && getClass() == other.getClass() && id != null)
? id.equals(((Question) other).id)
: (other == this);
}
@Override
public int hashCode() {
return (id != null)
? (getClass().hashCode() + id.hashCode())
: super.hashCode();
}
@Override
public String toString() {
return id;
}
}
and the QuestionBean
:
@ManagedBean (name="questionBean")
@ViewScoped
public class QuestionBean implements Serializable {
private List<Question> list;
//this was for a CRUD page; I deleted the other irrelevant code
private Question question = new Question();
private boolean edited;
@EJB
private QuestionDAO questionDAO;
@PostConstruct
public void init() {
list = questionDAO.getAll();
}
public List<Question> getList() {
return list;
}
public Question getQuestion() {
return question;
}
}