Retrieve class values from selectCheckboxMenu - jsf

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;
}

Related

Why selected items is always empty in the Bean for Primefaces selectCheckboxMenu

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

PrimeFaces auto complete return a null object

this is my xhtml page
<h:form id="order_search" prependId="flase">
<p:growl id="growl" showDetail="true" autoUpdate="true"
sticky="false" />
<h:panelGrid columns="5" style="margin-bottom:10px" cellpadding="5">
<p:outputLabel value="Customer Name : " for="ac_order" />
<p:autoComplete id="ac_order" value="#{orderSearchController.orderFromAutoC}"
completeMethod="#{orderSearchController.autoCompleteOrder}" var="order"
itemLabel="#{order.customerName}" itemValue="#{order}"
converter="#{orderConverter}" forceSelection="true" />
<p:commandButton id="selected" value="print" action="#{orderSearchController.printOrder}" />
</h:panelGrid>
</h:form>
and this is my backing bean
#Component
#ManagedBean
#ViewScoped
public class OrderSearchController implements Serializable{
private static final long serialVersionUID = 1L;
#ManagedProperty(value = "#{orderService}")
public OrderService orderService;
public List<Order> allOrders;
public List<Order> acFilterdOrders;
public Order orderFromAutoC;
#PostConstruct
public void Init() {
System.out.println("init gets called");
// allOrders = new ArrayList<>();
// orderFromAutoC = new Order();
allOrders = orderService.getAllOrders();
System.out.println("After sssssss ");
}
public List<Order> autoCompleteOrder(String query) {
acFilterdOrders = new ArrayList<Order>();
for (int i = 0; i < allOrders.size(); i++) {
if (allOrders.get(i).getCustomerName().toLowerCase().startsWith(query)) {
acFilterdOrders.add(allOrders.get(i));
}
}
return acFilterdOrders;
}
public String printOrder() {
System.out.println("Inside print");
System.out.println("Inside print : "+orderFromAutoC);
return null;
}
//Getters and Setters
}
and this is my converter code
#ManagedBean(name = "orderConverter")
#RequestScoped
public class OrderConverter implements Converter {
#ManagedProperty(value = "#{orderService}")
private OrderService orderService;
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String value) {
if (value != null && value.trim().length() > 0) {
return orderService.getOrderById(Integer.parseInt(value));
} else {
return null;
}
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
// TODO Auto-generated method stub
return null;
}
public OrderService getOrderService() {
return orderService;
}
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
}
the auto-complete component works fine but but when i tried to get the selected value from it in the backing bean it always return a null
The getAsString method is not implemented correctly as it is just returning the NULL value. The return value of getAsString method is passed as value in the getAsObject method based on which it get the value from the list. Here is an example for your reference . Value in the getAsObject method is the Id that is returned from getAsString method.
#Override
public Object getAsObject(FacesContext fc, UIComponent uic, String value) {
if(value != null && value.trim().length() > 0) {
MessageLogBean messageLogBean = (MessageLogBean) SessionUtility.getManagedBean("messageLogBean");
DeviceResponseDTO deviceResponseDTO = new DeviceResponseDTO();
deviceResponseDTO.setId(Integer.parseInt(value));
List<DeviceResponseDTO> deviceResponseDTOs = messageLogBean.getDeviceResponseDTOs();
int index = deviceResponseDTOs.indexOf(deviceResponseDTO);
if(null != deviceResponseDTOs && !deviceResponseDTOs.isEmpty()){
return deviceResponseDTOs.get(index);
}
return null;
}
else {
return null;
}
}
#Override
public String getAsString(FacesContext fc, UIComponent uic, Object object) {
if(object != null) {
return String.valueOf(((DeviceResponseDTO) object).getId());
}
else {
return null;
}
}

Injecting DAO give NullPointerException

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}" />

selectonemenu jsf on objects with converter

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;
}
}

JSF with Enum 'Validation Error: Value is not valid'

I have an enum whose code is like this -
public enum COSOptionType {
NOTAPPLICABLE,
OPTIONAL,
MANDATORY;
private String[] label = { "Not Applicable", "Optional", "Mandatory"};
#Override
public String toString() {
return label[this.ordinal()];
}
public static COSOptionType getCOSOption(String value) {
int ivalue = Integer.parseInt(value);
switch(ivalue) {
case 0:
return NOTAPPLICABLE;
case 1:
return OPTIONAL;
case 2:
return MANDATORY;
default:
throw new RuntimeException("Should not get this far ever!");
}
}
}
I have the converter to convert the enum type
public class COSEnumConverter implements Converter {
public Object getAsObject(FacesContext context, UIComponent comp, String value) {
return COSOptionType.getCOSOption(value);
}
public String getAsString(FacesContext context, UIComponent comp, Object obj) {
if (obj instanceof String) {
return (String) obj;
}
COSOptionType type = (COSOptionType) obj;
int index = type.ordinal();
return ""+index;
}
}
The view looks like this
<h:selectOneMenu value="#{controller.type}" id="smoking">
<f:selectItems value="#{jnyController.choices}" />
</h:selectOneMenu>
Here is the code for create choices
private List<SelectItem> createChoicies() {
List<SelectItem> list = new ArrayList<SelectItem>();
for (COSOptionType cos : COSOptionType.values()) {
SelectItem item = new SelectItem();
item.setLabel(cos.toString());
item.setValue("" + cos.ordinal());
list.add(item);
}
return list;
}
I do not understand why this would throw "validation error" all the time ? I can debug and see that the converter is working fine.
NOTE: I am using JSF 1.1
The root cause is that the converter returns a fullworthy COSOptionType object instead of the string "" + cos.ordinal() in getAsObject(), which thus don't appear at all in the existing options.
At any way, this approach is overcomplicated, especially the enum and the converter. I recommend you to reconsider this approach as follows:
Option:
package com.example;
public enum Option {
NOTAPPLICABLE("Not Applicable"),
OPTIONAL("Optional"),
MANDATORY("Mandatory");
private String label;
private Option(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
}
Bean:
package com.example;
import java.util.ArrayList;
import java.util.List;
import javax.faces.model.SelectItem;
public class Bean {
private List<SelectItem> options = new ArrayList<SelectItem>();
private Option option;
public Bean() {
for (Option option : Option.values()) {
options.add(new SelectItem(option, option.getLabel()));
}
}
public void submit() {
System.out.println(option);
}
public List<SelectItem> getOptions() {
return options;
}
public Option getOption() {
return option;
}
public void setOption(Option option) {
this.option = option;
}
}
OptionConverter:
package com.example;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
public class OptionConverter implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
return Option.valueOf(value);
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return ((Option) value).name();
}
}
faces-config.xml:
<managed-bean>
<managed-bean-name>bean</managed-bean-name>
<managed-bean-class>com.example.Bean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<converter>
<converter-class>com.example.OptionConverter</converter-class>
<converter-for-class>com.example.Option</converter-for-class>
</converter>
Relevant part of JSF page:
<h:form>
<h:selectOneMenu value="#{bean.option}">
<f:selectItems value="#{bean.options}" />
</h:selectOneMenu>
<h:commandButton value="submit" action="#{bean.submit}" />
<h:messages />
</h:form>
No need to hassle with Enum#ordinal() which is considered evil.
If you were using JSF 1.2 or newer which ships with a builtin generic EnumConverter, the OptionConverter is totally superfluous and can be safely removed.
Try item.setValue(cos) instead of item.setValue("" + cos.ordinal()).

Resources