i'm facing a problem with a Converter. In my xhtml file, i have a selectOneMenu with a list of object and i want to set an object in my managedBean.
If my managedBean has #SessionScoped, the object in the managedbean is filled but if the managedeban has #ViewScoped, the converter is never use and my object is null.
how to fix this problem ?
Xhtml :
<p:selectOneMenu value="#{rechercheBean.role}" converter="#{typConverter}">
<f:selectItems id="item" value="#{typBean.roles}" var="r" itemLabel="#{r.valeur}" itemValue="#{r}" />
</p:selectOneMenu>
typConverter :
public class TypConverter implements Converter{
#EJB
private TypFacadeLocal TypBean;
public Object getAsObject(FacesContext facesContext, UIComponent component, String submittedValue) {
if (submittedValue.trim().equals("")) {
return null;
}
else {
try {
Integer id = Integer.parseInt(submittedValue);
Typ typ = new Typ();
typ = TypBean.find(id);
return typ;
}
catch (NumberFormatException exception) {
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Conversion Error", "Typ non valide"));
}
}
}
public String getAsString(FacesContext facesContext, UIComponent component, Object value) {
if (value == null || value.equals("")) {
return "";
}
else {
return String.valueOf(((Typ) value).getId());
}
}
}
Tx a lot
The problem is the component c:when. With the attribut renderer of the component , there is no problem.
Related
I am using selectCheckboxMenu from Primefaces in a JSF project, the problem is that the "selectedDepartments" object in the Bean is always empty.
Here is the code:
Xhtml Page
<p:selectCheckboxMenu id="menu" label="name" style="width: 15rem" converter="#{departmentConverter}" value="#{StudentMB.selectedDepartments}"
multiple="true" filter="true" filterMatchMode="startsWith" panelStyle="width: 15rem" scrollHeight="250" >
<c:selectItems value="#{StudentMB.departmentList}" var="department" itemLabel="#{department.name}" itemValue="#{department}"/>
<p:ajax event="change" process="#this" update=":form2:dt-Students" global="false"/>
</p:selectCheckboxMenu>
The converter for selectCheckboxMenu:
#Named
#FacesConverter(value = "departmentConverter")
public class departmentConverter implements Converter {
#Inject
private departmentDAO departmentDAO;
#Override
public department getAsObject(FacesContext context, UIComponent component, String value) {
if (value != null && value.trim().length() > 0) {
try {
department c= departmentDAO.getdepartmentById(Integer.parseInt(value));
return c;
}
catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Conversion Error", "Not a valid country."));
}
}
else {
return null;
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value != null) {
department c=(department)value;
return String.valueOf(c.getId());
}
else {
return null;
}
}
}
The code of the Managed Bean
public class StudentMB implements Serializable{
private LazyDataModel<Student> lazyModel = null;
private List<department> departmentList;
private List<department> selectedDepartments;
#Inject
private departmentDAO departmentDAO;
#PostConstruct
public void init() {
this.selectedDepartments= new ArrayList<>();
this.departmentList= new ArrayList<>();
this.departmentList = this.departmentDAO.listDepartments();
lazyModel = new StudentLazyList(StudentDAO){
#Override
public List<Student> load(int first, int pageSize, Map<String, SortMeta> sortBy, Map<String, FilterMeta> filterBy) {
return load2(first, pageSize, sortBy, filterBy,selectedDepartments);
}
};
}
}
Thanks for help.
The solution is found for those who encounter the same problem. it was relative to the converter, indeed I don't know why we have to use a converter when it comes to a Pojo class because we already mentioned the name of class in the value property of selectItems.
Nevermind , here is the code that works
The selectCheckboxMenu component
<h:form id="form1">
<p:selectCheckboxMenu id="menu" label="department" converter="departmentConverter" value="#{studentMB.selectedDepartments}"
multiple="true" filter="true" filterMatchMode="startsWith" style="width: 15rem" panelStyle="width: 15rem" scrollHeight="250" >
<c:selectItems value="#{studentMB.departmentList}" var="department" itemLabel="#{department.name}" itemValue="#{department}"/>
<p:ajax event="change" update=":form2:dt-students"/>
</p:selectCheckboxMenu>
</h:form>
The converter class
#Named
#FacesConverter(value = "departmentConverter")
public class DepartmentConverter implements Converter {
#Override
public Department getAsObject(FacesContext context, UIComponent component, String value) {
if(value == null)
return null;
StudentMB data = context.getApplication().evaluateExpressionGet(context, "#{studentMB}", StudentMB.class);
int actualId=Integer.parseInt(value);
for(Department dep : data.getDepartmentList())
{
if(categ.getId()==actualId)
return dep;
}
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Conversion Error", "Not a valid department."));
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value != null) {
Department c=(Department)value;
return String.valueOf(c.getId());
}
else {
return null;
}
}
}
Hope this help
If I add stackElement first time it's ok, the output is:
list size = 1
But after adding second element I get error:
Error Rendering View[/tab.xhtml]: javax.el.PropertyNotFoundException:
/tab.xhtml #65,50 value="#{stackElement.name}": The class
'java.lang.String' does not have the property 'name'. ... Caused by:
javax.el.PropertyNotFoundException: The class 'java.lang.String' does
not have the property 'name'.
ERROR [io.undertow.request] (default task-4) UT005023: Exception
handling request to /Play/tab.xhtml: java.lang.IllegalStateException:
CDATA tags may not nest ...
Why does it happens?
Page
<h:form>
<p:commandButton update="stack" value="Use in expression" action="#{bean.tab}">
<f:param name="i" value="13" />
</p:commandButton>
<p:orderList id="stack" value="#{expression.list}" var="stackElement"
itemLabel="#{stackElement}" itemValue="#{stackElement}" controlsLocation="none" >
<!-- <p:ajax event="reorder" listener="#{expression.onReorder}" /> -->
<p:column>
<h:outputText value="#{stackElement.name}" />
</p:column>
</p:orderList>
</h:form>
bean
#ManagedBean #RequestScoped
public class Bean implements Serializable {
#ManagedProperty(value="#{expression}")
private Expression ex;
public void tab() {
ex.addStackElement( new StackElement((int) System.currentTimeMillis(), "tab") );
}
// getters-setters
bean
#ManagedBean #SessionScoped
public class Expression implements Serializable {
private List<StackElement> list = new ArrayList<StackElement>();
public void addStackElement(StackElement stackElement) {
list.add(stackElement);
System.out.println("list size = " + list.size());
}
// getters-setters
model
public class StackElement {
private int id;
private String name;
public StackElement(int id, String name) {
this.id = id;
this.name = name;
}
// getters-setters
converter
#FacesConverter("myConverter")
public class MyConverter implements Converter {
#Override
public Object getAsObject(FacesContext fc, UIComponent component, String value) {
if(value != null && value.trim().length() > 0) {
try {
Expression service = (Expression) fc.getExternalContext().getApplicationMap().get("expression");
return service.getStackElementByName(value);
} catch(NumberFormatException e) {
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Conversion Error", "Not a valid element name."));
}
}
else {
return null;
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object object) {
if(object != null) {
return String.valueOf(((StackElement) object).getName());
}
else {
return null;
}
}
}
There are few issues with your code.
You should use converter="myConverter" on your <p:orderList> component.
Expression bean is of SessionScoped. But you are getting it from ApplicationScope.
Change it to
Expression service = (Expression) fc.getExternalContext().getSessionMap().get("expression");
After making these changes its working.
I have a <p:selectCheckboxMenu> and I want to get the selected values back in bean. But the value I receive
when I select an item from the menu it's a string, representing the type field from the CategorizationBean.
I just want when I select an item from the table, to get the whole CategorizationBean structure in the bean.
This is the snippet from the xhtml page:
<p:selectCheckboxMenu label="Categorization"
value="#alertMB.selectedCategories}"
converter="com.converter.CategoryConverter">
<f:selectItems value="#{alertMB.categoryDomainEntry}"
var="category"
itemLabel="#{category.type}"
itemValue="#{category}"/>
</p:selectCheckboxMenu>
Snippet from bean:
public List<CategorizationBean> getSelectedCategories() {
return selectedCategories;
}
public void setSelectedCategories(List<CategorizationBean> selectedCategories) {
this.selectedCategories = selectedCategories;
}
public class CategorizationBean implements Serializable{
private String type;
private long id;
I think that you have missed by using a list of beans, I use this example and it works:
<p:selectCheckboxMenu id="slctRdBtn"
value="#{yourBean.compLovDtgrid}"
converter="compLovDtgridConverter">
<f:selectItems
value="#{yourBean.listCompLovDtgrid}"
var="rdbtn" itemLabel="#{rdbtn.vjlrLibelleRep}"
itemValue="#{rdbtn}" />
</p:selectCheckboxMenu>
and for the converter:
#FacesConverter(forClass=CompLovDtgrid.class , value="compLovDtgridConverter")
public class CompLovDtgridConverter implements Converter{
#Override
public String getAsString(FacesContext context, UIComponent component, Object value)
{
return (value instanceof CompLovDtgrid) ? ((CompLovDtgrid) value).getVjlrCodeRep() : null;
}
#Override
public Object getAsObject(FacesContext context, UIComponent component,String value)
{
if(value == null)
return null;
YourBean data = context.getApplication().evaluateExpressionGet(context, "#{yourBean}", YourBean.class);
for(CompLovDtgrid compLovDtgrid : data.getListCompLovDtgrid())
{
if(compLovDtgrid.getVjlrCodeRep().equals(value))
return compLovDtgrid;
}
throw new ConverterException(new FacesMessage(String.format("Cannot convert %s to CompLovDtgrid", value)));
}
}
and for the list, I use:
public List<CompLovDtgrid> getListCompLovDtgrid()
{
return listCompLovDtgrid;
}
public void setListCompLovDtgrid(List<CompLovDtgrid> listCompLovDtgrid) {
this.listCompLovDtgrid = listCompLovDtgrid;
}
Using the following Bean, I fill a form with countries:
#ManagedBean
#RequestScoped
public class CreateUser {
#EJB
private ParticipantDAO participantDAO;
#EJB
private CountryDAO countryDAO;
private List<Country> countries = new ArrayList<Country>();
. . .
. . .
. . .
#PostConstruct
public void init() {
countries = countryDAO.getAllCountries();
}
In the form I've to use a Converter:
<h:selectOneMenu id="country" value="#{createUser.user.country}" required="true" requiredMessage="Please select a country." converter="#{countryConverter}" >
<f:selectItem itemValue="#{null}" itemLabel="-- select one --" />
<f:selectItems value="#{createUser.countries}" var="country" itemValue="#{country}" itemLabel="#{country.country}" />
</h:selectOneMenu>
The Converter give a NullPointerException seems because it's unable to inject CountryDAO:
#ManagedBean
#RequestScoped
#FacesConverter(forClass = Country.class)
public class CountryConverter implements Converter {
#EJB
private CountryDAO countryDAO;
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (!(value instanceof Country)) {
return null;
}
return String.valueOf(((Country) value).getId());
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || value.isEmpty()) {
return null;
}
try {
System.out.println("Converter Value: " + value);
Country c = countryDAO.find(Long.valueOf(value));
System.out.println("Converter: " + c.getCountry());
return c;
} catch (Exception e) {
throw new ConverterException(new FacesMessage(String.format("Cannot convert %s to Country %s %d", value, e.toString(), Long.valueOf((value)))), e);
}
}
}
In the console I see the "Converted Value" message but not the "CountryDAO find" that should be printed by createDAO.find method.
#Stateless
#LocalBean
public class CountryDAO {
public CountryDAO() {
}
#PersistenceContext
private EntityManager em;
#Resource
SessionContext context;
public List<Country> getAllCountries() {
TypedQuery<Country> query = em.createNamedQuery(Country.FIND_ALL, Country.class);
return query.getResultList();
}
public Country find(Long id) {
System.out.println("CountryDAO find");
Country c = em.find(Country.class, id);
System.out.println(c.getCountry());
return c;
}
I tried the solution reported to Inject a EJB into a JSF converter with JEE6 (I don't know if I put the code in the correct location). I put it in the converter (and I obtain the NullPointerException):
#ManagedBean
#FacesConverter(forClass = Country.class)
public class CountryConverter implements Converter {
// #EJB
// private CountryDAO countryDAO;
private InitialContext ic;
private CountryDAO countryDAO;
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (!(value instanceof Country)) {
return null;
}
return String.valueOf(((Country) value).getId());
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || value.isEmpty()) {
return null;
}
System.out.println("Converter Value: " + value);
try {
try {
ic = new InitialContext();
countryDAO = (CountryDAO) ic.lookup("java:global/DAO/CountryDAO");
} catch (NamingException e) {
}
Country c = countryDAO.find(Long.valueOf(value));
System.out.println("Converter: " + c.getCountry());
return c;
} catch (Exception e) {
throw new ConverterException(new FacesMessage(String.format("Cannot convert %s to Country %s %d", value, e.toString(), Long.valueOf((value)))), e);
}
}
I was having the same problem in the some other project, where I was using a converter for some primefaces component. I solved the problem the CDI way.
All you have to do is annotate your converter class with #Named (and inject the DAO class via #Inject (JEE6), and not with JEE5 - #EJB).
You reference your converter with binding attribute like:
<f:converter binding="#{countryConverter}" />
Here is my SelectOneMenu
<h:selectOneMenu value="#{bean.myObject}" >
<f:ajax render="componentToRender" listener="#{bean.onSelect}"/>
<f:converter converterId="myObjectConverter" />
<f:selectItem itemLabel="None" itemValue="#{null}" />
<f:selectItems value="#{bean.objects}" var="object" itemValue="#{object}" itemLabel="#{object.name}" />
</h:selectOneMenu>
And my converter
#FacesConverter("myObjectConverter")
public class MyObjectConverter implements Converter{
private List<MyObject> objects;
public MyObjectConverter(){
this.objects = MyController.getAllMyObjects();
}
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if(!StringUtils.isInteger(value)) {
return null;
}
return this.getMyObject(value);
}
public String getAsString(FacesContext context, UIComponent component, Object value) {
if(value == null) {
return null;
}
return String.valueOf(((MyObject) value).getId()).toString();
}
public MyObject getMyObject(String id) {
Iterator<MyObject > iterator = this.objects.iterator();
while(iterator.hasNext()) {
MyObject object = iterator.next();
if(object.getId() == Integer.valueOf(id).intValue()) {
return object;
}
}
return null;
}
}
The problem is that my ajax listener is never called and my component never rendered.
Is there something wrong with my converter or selectOneMenu? I follow an example and I can't figure the mistake out.
BTW : my simple method in the bean
public void onSelect() {
System.out.println(this.myObject);
if(this.myObject != null) {
System.out.println(this.myObject.getName());
}
}
I already had a problem like this and I changed my selected value from object to id. But here I want to make it work with objects because I know it's possible.
Thanks
I have the solution. I had to override the "equals" method in MyObject class!
Thanks.
EDIT: the code
#Override
public boolean equals(Object obj) {
if(this.id == ((MyObject) obj).id) {
return true;
}else {
return false;
}
}