F:selectItems showing the class not a value - jsf

I'm new to facelets and I have generated a project using netbeans but I struggling with the tag.
I have
<h:selectOneMenu id="country" value="#{organisation.organisation.country}" title="Country" >
<f:selectItems value="#{country.countryItemsAvailableSelectOne}"/>
</h:selectOneMenu>
In the select I get classpath.Country[iso=GB] which I can see is an object but I really want to see the the country.prinableName value.
I've looked at this for half a day and have drawn a blank
Thanks for any help

Since you're talking about Facelets, I'll assume JSF 2.x.
To start, HTML is one and all String. JSF generates HTML. By default, non-String Java objects are by toString() method converted to their String representation while JSF generates the HTML. To properly convert between those Java objects and String, you need a Converter.
I assume that your Country object has already the equals() method properly implemented, otherwise validation will later fail with "Validation error: Value not valid" because the selected object doesn't return true on testing the equals() for any of the available items.
I'll also make a little change in the naming since #{country} is a confusing managed bean name because it does apparently not represent an instance of the Country class. I'll call it Data which should hold application wide data.
#ManagedBean
#ApplicaitionScoped
public class Data {
private static final List<Country> COUNTRIES = populateItSomehow();
public List<Country> getCountries() {
return COUNTRIES;
}
// ...
}
I'll assume that the Country class has two properties code and name. I'll assume that the managed bean which receives the selected country has a private Country country property. In your <f:selectItems>, you need to loop over #{data.countries} and specify the country object as item value and the country name as item label.
<h:selectOneMenu value="#{bean.country}">
<f:selectItems value="#{data.countries}" var="country" itemValue="#{country}" itemLabel="#{country.name}" />
</h:selectOneMenu>
Now, you need to create a Converter for the Country class. We'll convert based on the country code which is unique for every country (right?). In the getAsString() you implement code which converts the Java object to its unique String representation which is to be used in HTML. In getAsObject() you implement code which converts the unique HTML String representation back to the Java object.
#FacesConverter(forClass=Country.class)
public class CountryConverter implements Converter {
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return (value instanceof Country) ? ((Country) value).getCode() : null;
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null) {
return null;
}
Data data = context.getApplication().evaluateExpressionGet(context, "#{data}", Data.class);
for (Country country : data.getCountries()) {
if (country.getCode().equals(value)) {
return country;
}
}
throw new ConverterException(new FacesMessage(String.format("Cannot convert %s to Country", value)));
}
}
The #FacesConverter will register it automatically in JSF and JSF will automatically use it whenever it encounters a value expression of the Country type. Ultimately, you end up with country code as item value and country name as item label. JSF will convert the submitted country code back to a fullworthy Country object upon form submission.
In JSF 1.x the principle is not much different. In this blog you can find two basic kickoff examples: Objects in h:selectOneMenu.

What happened to you, selectOneMenu call the toString() method for all given objects.
You've to use selectitems or a simple converter to manage that. A very simple example:
price.xhtml:
<h:selectOneMenu id="priceMenu" value="#{priceBean.selectedPrice}">
<f:selectItems value="#{priceBean.prices}" />
</h:selectOneMenu>
PriceBean.java:
..
private String selectedPrice;
..
public String getSelectedPrice() {
return selectedPrice;
}
public void setSelectedPrice(String newPrice) {
selectedPrice = newPrice;
}
..
public List<SelectItem> getPrices() {
List<SelectItem> retVal = new ArrayList<SelectItem>();
retVal.add(new SelectItem("2"));
retVal.add(new SelectItem("4"));
retVal.add(new SelectItem("6"));
return retVal;
}
Further informations about the SelectItem. If you want to use a specially object directly, for example an object called Price, you have to use a converter. Here an example is shown and here.

If you add editable="true" in your
<h:selectOneMenu value="#{bean.country}">
Then you'll get an unexpected String value (not from getAsString()) in the converter method:
public Object getAsObject(FacesContext context, UIComponent component, String value) { }

Related

How to use selectOneMenu in jsf with value of object not String? [duplicate]

I have problems understanding how to use selection in JSF 2 with POJO/entity effectively. For example, I'm trying to select a Warehouse entity via the below dropdown:
<h:selectOneMenu value="#{bean.selectedWarehouse}">
<f:selectItem itemLabel="Choose one .." itemValue="#{null}" />
<f:selectItems value="#{bean.availableWarehouses}" />
</h:selectOneMenu>
And the below managed bean:
#Named
#ViewScoped
public class Bean {
private Warehouse selectedWarehouse;
private List<SelectItem> availableWarehouses;
// ...
#PostConstruct
public void init() {
// ...
availableWarehouses = new ArrayList<>();
for (Warehouse warehouse : warehouseService.listAll()) {
availableWarehouses.add(new SelectItem(warehouse, warehouse.getName()));
}
}
// ...
}
Notice that I use the whole Warehouse entity as the value of SelectItem.
When I submit the form, this fails with the following faces message:
Conversion Error setting value 'com.example.Warehouse#cafebabe' for 'null Converter'.
I was hoping that JSF could just set the correct Warehouse object to my managed bean when I wrap it in a SelectItem. Wrapping my entity inside the SelectItem was meant to skip creating a Converter for my entity.
Do I really have to use a Converter whenever I want to make use of entities in my <h:selectOneMenu>? It should for JSF be possible to just extract the selected item from the list of available items. If I really have to use a converter, what is the practical way of doing it? So far I came up to this:
Create a Converter implementation for the entity.
Overriding the getAsString(). I think I don't need this since the label property of the SelectItem will be used to display the dropdown option label.
Overriding the getAsObject(). I think this will be used to return the correct SelectItem or entity depending on the type of the selected field defined in the managed bean.
The getAsObject() confuses me. What is the efficient way to do this? Having the string value, how do I get the associated entity object? Should I query the entity object from the service object based on the string value and return the entity? Or perhaps somehow I can access the list of the entities that form the selection items, loop them to find the correct entity, and return the entity?
What is the normal approach of this?
Introduction
JSF generates HTML. HTML is in Java terms basically one large String. To represent Java objects in HTML, they have to be converted to String. Also, when a HTML form is submitted, the submitted values are treated as String in the HTTP request parameters. Under the covers, JSF extracts them from the HttpServletRequest#getParameter() which returns String.
To convert between a non-standard Java object (i.e. not a String, Number or Boolean for which EL has builtin conversions, or Date/LocalDate/ZonedDateTime for which JSF provides builtin <f:convertDateTime> tag), you really have to supply a custom Converter. The SelectItem has no special purpose at all. It's just a leftover from JSF 1.x when it wasn't possible to supply e.g. List<Warehouse> directly to <f:selectItems>. It has also no special treatment as to labels and conversion.
getAsString()
You need to implement getAsString() method in such way that the desired Java object is been represented in an unique String representation which can be used as HTTP request parameter. Normally, the technical ID (the database primary key) is used here.
public String getAsString(FacesContext context, UIComponent component, Object modelValue) {
if (modelValue == null) {
return ""; // Never return null here!
}
if (modelValue instanceof Warehouse) {
return String.valueOf(((Warehouse) modelValue).getId());
} else {
throw new ConverterException(new FacesMessage(modelValue + " is not a valid Warehouse"));
}
}
Note that returning an empty string in case of a null/empty model value is significant and required by the javadoc:
Returns: a zero-length String if value is null, otherwise the result of the conversion
Otherwise the generated <option> will not have a value attribute and by default send the item label back into getAsObject(). See also Using a "Please select" f:selectItem with null/empty value inside a p:selectOneMenu.
getAsObject()
You need to implement getAsObject() in such way that exactly that String representation as returned by getAsString() can be converted back to exactly the same Java object specified as modelValue in getAsString().
public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
if (submittedValue == null || submittedValue.isEmpty()) {
return null;
}
try {
return warehouseService.find(Long.valueOf(submittedValue));
} catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage(submittedValue + " is not a valid Warehouse ID"), e);
}
}
In other words, you must be technically able to pass back the returned object as modelValue argument of getAsString() and then pass back the obtained string as submittedValue argument of getAsObject() in an infinite loop.
Usage
Finally just annotate the Converter with #FacesConverter to hook on the object type in question, JSF will then automatically take care of conversion when Warehouse type ever comes into the picture:
#FacesConverter(forClass=Warehouse.class)
That was the "canonical" JSF approach. It's after all not very effective as it could indeed also just have grabbed the item from the <f:selectItems>. But the most important point of a Converter is that it returns an unique String representation, so that the Java object could be identified by a simple String suitable for passing around in HTTP and HTML.
Generic converter based on toString()
JSF utility library OmniFaces has a SelectItemsConverter which works based on toString() outcome of the entity. This way you do not need to fiddle with getAsObject() and expensive business/database operations anymore. For some concrete use examples, see also the showcase.
To use it, just register it as below:
<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
And make sure that the toString() of your Warehouse entity returns an unique representation of the entity. You could for instance directly return the ID:
#Override
public String toString() {
return String.valueOf(id);
}
Or something more readable/reusable:
#Override
public String toString() {
return "Warehouse[id=" + id + "]";
}
See also:
How to populate options of h:selectOneMenu from database?
Generic JSF entity converter - so that you don't need to write a converter for every entity.
Using enums in JSF selectitems - enums needs to be treated a bit differently
How to inject #EJB, #PersistenceContext, #Inject, #Autowired, etc in #FacesConverter?
Unrelated to the problem, since JSF 2.0 it's not explicitly required anymore to have a List<SelectItem> as <f:selectItem> value. Just a List<Warehouse> would also suffice.
<h:selectOneMenu value="#{bean.selectedWarehouse}">
<f:selectItem itemLabel="Choose one .." itemValue="#{null}" />
<f:selectItems value="#{bean.availableWarehouses}" var="warehouse"
itemLabel="#{warehouse.name}" itemValue="#{warehouse}" />
</h:selectOneMenu>
private Warehouse selectedWarehouse;
private List<Warehouse> availableWarehouses;
Example of JSF generic converter with ABaseEntity and identifier:
ABaseEntity.java
public abstract class ABaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
public abstract Long getIdentifier();
}
SelectItemToEntityConverter.java
#FacesConverter(value = "SelectItemToEntityConverter")
public class SelectItemToEntityConverter implements Converter {
#Override
public Object getAsObject(FacesContext ctx, UIComponent comp, String value) {
Object o = null;
if (!(value == null || value.isEmpty())) {
o = this.getSelectedItemAsEntity(comp, value);
}
return o;
}
#Override
public String getAsString(FacesContext ctx, UIComponent comp, Object value) {
String s = "";
if (value != null) {
s = ((ABaseEntity) value).getIdentifier().toString();
}
return s;
}
private ABaseEntity getSelectedItemAsEntity(UIComponent comp, String value) {
ABaseEntity item = null;
List<ABaseEntity> selectItems = null;
for (UIComponent uic : comp.getChildren()) {
if (uic instanceof UISelectItems) {
Long itemId = Long.valueOf(value);
selectItems = (List<ABaseEntity>) ((UISelectItems) uic).getValue();
if (itemId != null && selectItems != null && !selectItems.isEmpty()) {
Predicate<ABaseEntity> predicate = i -> i.getIdentifier().equals(itemId);
item = selectItems.stream().filter(predicate).findFirst().orElse(null);
}
}
}
return item;
}
}
And usage:
<p:selectOneMenu id="somItems" value="#{exampleBean.selectedItem}" converter="SelectItemToEntityConverter">
<f:selectItem itemLabel="< select item >" itemValue="#{null}"/>
<f:selectItems value="#{exampleBean.availableItems}" var="item" itemLabel="${item.identifier}" itemValue="#{item}"/>
</p:selectOneMenu>

Why selectCheckboxMenu passes values as its toString? [duplicate]

I have problems understanding how to use selection in JSF 2 with POJO/entity effectively. For example, I'm trying to select a Warehouse entity via the below dropdown:
<h:selectOneMenu value="#{bean.selectedWarehouse}">
<f:selectItem itemLabel="Choose one .." itemValue="#{null}" />
<f:selectItems value="#{bean.availableWarehouses}" />
</h:selectOneMenu>
And the below managed bean:
#Named
#ViewScoped
public class Bean {
private Warehouse selectedWarehouse;
private List<SelectItem> availableWarehouses;
// ...
#PostConstruct
public void init() {
// ...
availableWarehouses = new ArrayList<>();
for (Warehouse warehouse : warehouseService.listAll()) {
availableWarehouses.add(new SelectItem(warehouse, warehouse.getName()));
}
}
// ...
}
Notice that I use the whole Warehouse entity as the value of SelectItem.
When I submit the form, this fails with the following faces message:
Conversion Error setting value 'com.example.Warehouse#cafebabe' for 'null Converter'.
I was hoping that JSF could just set the correct Warehouse object to my managed bean when I wrap it in a SelectItem. Wrapping my entity inside the SelectItem was meant to skip creating a Converter for my entity.
Do I really have to use a Converter whenever I want to make use of entities in my <h:selectOneMenu>? It should for JSF be possible to just extract the selected item from the list of available items. If I really have to use a converter, what is the practical way of doing it? So far I came up to this:
Create a Converter implementation for the entity.
Overriding the getAsString(). I think I don't need this since the label property of the SelectItem will be used to display the dropdown option label.
Overriding the getAsObject(). I think this will be used to return the correct SelectItem or entity depending on the type of the selected field defined in the managed bean.
The getAsObject() confuses me. What is the efficient way to do this? Having the string value, how do I get the associated entity object? Should I query the entity object from the service object based on the string value and return the entity? Or perhaps somehow I can access the list of the entities that form the selection items, loop them to find the correct entity, and return the entity?
What is the normal approach of this?
Introduction
JSF generates HTML. HTML is in Java terms basically one large String. To represent Java objects in HTML, they have to be converted to String. Also, when a HTML form is submitted, the submitted values are treated as String in the HTTP request parameters. Under the covers, JSF extracts them from the HttpServletRequest#getParameter() which returns String.
To convert between a non-standard Java object (i.e. not a String, Number or Boolean for which EL has builtin conversions, or Date/LocalDate/ZonedDateTime for which JSF provides builtin <f:convertDateTime> tag), you really have to supply a custom Converter. The SelectItem has no special purpose at all. It's just a leftover from JSF 1.x when it wasn't possible to supply e.g. List<Warehouse> directly to <f:selectItems>. It has also no special treatment as to labels and conversion.
getAsString()
You need to implement getAsString() method in such way that the desired Java object is been represented in an unique String representation which can be used as HTTP request parameter. Normally, the technical ID (the database primary key) is used here.
public String getAsString(FacesContext context, UIComponent component, Object modelValue) {
if (modelValue == null) {
return ""; // Never return null here!
}
if (modelValue instanceof Warehouse) {
return String.valueOf(((Warehouse) modelValue).getId());
} else {
throw new ConverterException(new FacesMessage(modelValue + " is not a valid Warehouse"));
}
}
Note that returning an empty string in case of a null/empty model value is significant and required by the javadoc:
Returns: a zero-length String if value is null, otherwise the result of the conversion
Otherwise the generated <option> will not have a value attribute and by default send the item label back into getAsObject(). See also Using a "Please select" f:selectItem with null/empty value inside a p:selectOneMenu.
getAsObject()
You need to implement getAsObject() in such way that exactly that String representation as returned by getAsString() can be converted back to exactly the same Java object specified as modelValue in getAsString().
public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
if (submittedValue == null || submittedValue.isEmpty()) {
return null;
}
try {
return warehouseService.find(Long.valueOf(submittedValue));
} catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage(submittedValue + " is not a valid Warehouse ID"), e);
}
}
In other words, you must be technically able to pass back the returned object as modelValue argument of getAsString() and then pass back the obtained string as submittedValue argument of getAsObject() in an infinite loop.
Usage
Finally just annotate the Converter with #FacesConverter to hook on the object type in question, JSF will then automatically take care of conversion when Warehouse type ever comes into the picture:
#FacesConverter(forClass=Warehouse.class)
That was the "canonical" JSF approach. It's after all not very effective as it could indeed also just have grabbed the item from the <f:selectItems>. But the most important point of a Converter is that it returns an unique String representation, so that the Java object could be identified by a simple String suitable for passing around in HTTP and HTML.
Generic converter based on toString()
JSF utility library OmniFaces has a SelectItemsConverter which works based on toString() outcome of the entity. This way you do not need to fiddle with getAsObject() and expensive business/database operations anymore. For some concrete use examples, see also the showcase.
To use it, just register it as below:
<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
And make sure that the toString() of your Warehouse entity returns an unique representation of the entity. You could for instance directly return the ID:
#Override
public String toString() {
return String.valueOf(id);
}
Or something more readable/reusable:
#Override
public String toString() {
return "Warehouse[id=" + id + "]";
}
See also:
How to populate options of h:selectOneMenu from database?
Generic JSF entity converter - so that you don't need to write a converter for every entity.
Using enums in JSF selectitems - enums needs to be treated a bit differently
How to inject #EJB, #PersistenceContext, #Inject, #Autowired, etc in #FacesConverter?
Unrelated to the problem, since JSF 2.0 it's not explicitly required anymore to have a List<SelectItem> as <f:selectItem> value. Just a List<Warehouse> would also suffice.
<h:selectOneMenu value="#{bean.selectedWarehouse}">
<f:selectItem itemLabel="Choose one .." itemValue="#{null}" />
<f:selectItems value="#{bean.availableWarehouses}" var="warehouse"
itemLabel="#{warehouse.name}" itemValue="#{warehouse}" />
</h:selectOneMenu>
private Warehouse selectedWarehouse;
private List<Warehouse> availableWarehouses;
Example of JSF generic converter with ABaseEntity and identifier:
ABaseEntity.java
public abstract class ABaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
public abstract Long getIdentifier();
}
SelectItemToEntityConverter.java
#FacesConverter(value = "SelectItemToEntityConverter")
public class SelectItemToEntityConverter implements Converter {
#Override
public Object getAsObject(FacesContext ctx, UIComponent comp, String value) {
Object o = null;
if (!(value == null || value.isEmpty())) {
o = this.getSelectedItemAsEntity(comp, value);
}
return o;
}
#Override
public String getAsString(FacesContext ctx, UIComponent comp, Object value) {
String s = "";
if (value != null) {
s = ((ABaseEntity) value).getIdentifier().toString();
}
return s;
}
private ABaseEntity getSelectedItemAsEntity(UIComponent comp, String value) {
ABaseEntity item = null;
List<ABaseEntity> selectItems = null;
for (UIComponent uic : comp.getChildren()) {
if (uic instanceof UISelectItems) {
Long itemId = Long.valueOf(value);
selectItems = (List<ABaseEntity>) ((UISelectItems) uic).getValue();
if (itemId != null && selectItems != null && !selectItems.isEmpty()) {
Predicate<ABaseEntity> predicate = i -> i.getIdentifier().equals(itemId);
item = selectItems.stream().filter(predicate).findFirst().orElse(null);
}
}
}
return item;
}
}
And usage:
<p:selectOneMenu id="somItems" value="#{exampleBean.selectedItem}" converter="SelectItemToEntityConverter">
<f:selectItem itemLabel="< select item >" itemValue="#{null}"/>
<f:selectItems value="#{exampleBean.availableItems}" var="item" itemLabel="${item.identifier}" itemValue="#{item}"/>
</p:selectOneMenu>

PrimeFaces Casting And NumberFormat Exception [duplicate]

I have problems understanding how to use selection in JSF 2 with POJO/entity effectively. For example, I'm trying to select a Warehouse entity via the below dropdown:
<h:selectOneMenu value="#{bean.selectedWarehouse}">
<f:selectItem itemLabel="Choose one .." itemValue="#{null}" />
<f:selectItems value="#{bean.availableWarehouses}" />
</h:selectOneMenu>
And the below managed bean:
#Named
#ViewScoped
public class Bean {
private Warehouse selectedWarehouse;
private List<SelectItem> availableWarehouses;
// ...
#PostConstruct
public void init() {
// ...
availableWarehouses = new ArrayList<>();
for (Warehouse warehouse : warehouseService.listAll()) {
availableWarehouses.add(new SelectItem(warehouse, warehouse.getName()));
}
}
// ...
}
Notice that I use the whole Warehouse entity as the value of SelectItem.
When I submit the form, this fails with the following faces message:
Conversion Error setting value 'com.example.Warehouse#cafebabe' for 'null Converter'.
I was hoping that JSF could just set the correct Warehouse object to my managed bean when I wrap it in a SelectItem. Wrapping my entity inside the SelectItem was meant to skip creating a Converter for my entity.
Do I really have to use a Converter whenever I want to make use of entities in my <h:selectOneMenu>? It should for JSF be possible to just extract the selected item from the list of available items. If I really have to use a converter, what is the practical way of doing it? So far I came up to this:
Create a Converter implementation for the entity.
Overriding the getAsString(). I think I don't need this since the label property of the SelectItem will be used to display the dropdown option label.
Overriding the getAsObject(). I think this will be used to return the correct SelectItem or entity depending on the type of the selected field defined in the managed bean.
The getAsObject() confuses me. What is the efficient way to do this? Having the string value, how do I get the associated entity object? Should I query the entity object from the service object based on the string value and return the entity? Or perhaps somehow I can access the list of the entities that form the selection items, loop them to find the correct entity, and return the entity?
What is the normal approach of this?
Introduction
JSF generates HTML. HTML is in Java terms basically one large String. To represent Java objects in HTML, they have to be converted to String. Also, when a HTML form is submitted, the submitted values are treated as String in the HTTP request parameters. Under the covers, JSF extracts them from the HttpServletRequest#getParameter() which returns String.
To convert between a non-standard Java object (i.e. not a String, Number or Boolean for which EL has builtin conversions, or Date/LocalDate/ZonedDateTime for which JSF provides builtin <f:convertDateTime> tag), you really have to supply a custom Converter. The SelectItem has no special purpose at all. It's just a leftover from JSF 1.x when it wasn't possible to supply e.g. List<Warehouse> directly to <f:selectItems>. It has also no special treatment as to labels and conversion.
getAsString()
You need to implement getAsString() method in such way that the desired Java object is been represented in an unique String representation which can be used as HTTP request parameter. Normally, the technical ID (the database primary key) is used here.
public String getAsString(FacesContext context, UIComponent component, Object modelValue) {
if (modelValue == null) {
return ""; // Never return null here!
}
if (modelValue instanceof Warehouse) {
return String.valueOf(((Warehouse) modelValue).getId());
} else {
throw new ConverterException(new FacesMessage(modelValue + " is not a valid Warehouse"));
}
}
Note that returning an empty string in case of a null/empty model value is significant and required by the javadoc:
Returns: a zero-length String if value is null, otherwise the result of the conversion
Otherwise the generated <option> will not have a value attribute and by default send the item label back into getAsObject(). See also Using a "Please select" f:selectItem with null/empty value inside a p:selectOneMenu.
getAsObject()
You need to implement getAsObject() in such way that exactly that String representation as returned by getAsString() can be converted back to exactly the same Java object specified as modelValue in getAsString().
public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
if (submittedValue == null || submittedValue.isEmpty()) {
return null;
}
try {
return warehouseService.find(Long.valueOf(submittedValue));
} catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage(submittedValue + " is not a valid Warehouse ID"), e);
}
}
In other words, you must be technically able to pass back the returned object as modelValue argument of getAsString() and then pass back the obtained string as submittedValue argument of getAsObject() in an infinite loop.
Usage
Finally just annotate the Converter with #FacesConverter to hook on the object type in question, JSF will then automatically take care of conversion when Warehouse type ever comes into the picture:
#FacesConverter(forClass=Warehouse.class)
That was the "canonical" JSF approach. It's after all not very effective as it could indeed also just have grabbed the item from the <f:selectItems>. But the most important point of a Converter is that it returns an unique String representation, so that the Java object could be identified by a simple String suitable for passing around in HTTP and HTML.
Generic converter based on toString()
JSF utility library OmniFaces has a SelectItemsConverter which works based on toString() outcome of the entity. This way you do not need to fiddle with getAsObject() and expensive business/database operations anymore. For some concrete use examples, see also the showcase.
To use it, just register it as below:
<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
And make sure that the toString() of your Warehouse entity returns an unique representation of the entity. You could for instance directly return the ID:
#Override
public String toString() {
return String.valueOf(id);
}
Or something more readable/reusable:
#Override
public String toString() {
return "Warehouse[id=" + id + "]";
}
See also:
How to populate options of h:selectOneMenu from database?
Generic JSF entity converter - so that you don't need to write a converter for every entity.
Using enums in JSF selectitems - enums needs to be treated a bit differently
How to inject #EJB, #PersistenceContext, #Inject, #Autowired, etc in #FacesConverter?
Unrelated to the problem, since JSF 2.0 it's not explicitly required anymore to have a List<SelectItem> as <f:selectItem> value. Just a List<Warehouse> would also suffice.
<h:selectOneMenu value="#{bean.selectedWarehouse}">
<f:selectItem itemLabel="Choose one .." itemValue="#{null}" />
<f:selectItems value="#{bean.availableWarehouses}" var="warehouse"
itemLabel="#{warehouse.name}" itemValue="#{warehouse}" />
</h:selectOneMenu>
private Warehouse selectedWarehouse;
private List<Warehouse> availableWarehouses;
Example of JSF generic converter with ABaseEntity and identifier:
ABaseEntity.java
public abstract class ABaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
public abstract Long getIdentifier();
}
SelectItemToEntityConverter.java
#FacesConverter(value = "SelectItemToEntityConverter")
public class SelectItemToEntityConverter implements Converter {
#Override
public Object getAsObject(FacesContext ctx, UIComponent comp, String value) {
Object o = null;
if (!(value == null || value.isEmpty())) {
o = this.getSelectedItemAsEntity(comp, value);
}
return o;
}
#Override
public String getAsString(FacesContext ctx, UIComponent comp, Object value) {
String s = "";
if (value != null) {
s = ((ABaseEntity) value).getIdentifier().toString();
}
return s;
}
private ABaseEntity getSelectedItemAsEntity(UIComponent comp, String value) {
ABaseEntity item = null;
List<ABaseEntity> selectItems = null;
for (UIComponent uic : comp.getChildren()) {
if (uic instanceof UISelectItems) {
Long itemId = Long.valueOf(value);
selectItems = (List<ABaseEntity>) ((UISelectItems) uic).getValue();
if (itemId != null && selectItems != null && !selectItems.isEmpty()) {
Predicate<ABaseEntity> predicate = i -> i.getIdentifier().equals(itemId);
item = selectItems.stream().filter(predicate).findFirst().orElse(null);
}
}
}
return item;
}
}
And usage:
<p:selectOneMenu id="somItems" value="#{exampleBean.selectedItem}" converter="SelectItemToEntityConverter">
<f:selectItem itemLabel="< select item >" itemValue="#{null}"/>
<f:selectItems value="#{exampleBean.availableItems}" var="item" itemLabel="${item.identifier}" itemValue="#{item}"/>
</p:selectOneMenu>

SelectOneMenu - Primefaces not record at the database [duplicate]

I have problems understanding how to use selection in JSF 2 with POJO/entity effectively. For example, I'm trying to select a Warehouse entity via the below dropdown:
<h:selectOneMenu value="#{bean.selectedWarehouse}">
<f:selectItem itemLabel="Choose one .." itemValue="#{null}" />
<f:selectItems value="#{bean.availableWarehouses}" />
</h:selectOneMenu>
And the below managed bean:
#Named
#ViewScoped
public class Bean {
private Warehouse selectedWarehouse;
private List<SelectItem> availableWarehouses;
// ...
#PostConstruct
public void init() {
// ...
availableWarehouses = new ArrayList<>();
for (Warehouse warehouse : warehouseService.listAll()) {
availableWarehouses.add(new SelectItem(warehouse, warehouse.getName()));
}
}
// ...
}
Notice that I use the whole Warehouse entity as the value of SelectItem.
When I submit the form, this fails with the following faces message:
Conversion Error setting value 'com.example.Warehouse#cafebabe' for 'null Converter'.
I was hoping that JSF could just set the correct Warehouse object to my managed bean when I wrap it in a SelectItem. Wrapping my entity inside the SelectItem was meant to skip creating a Converter for my entity.
Do I really have to use a Converter whenever I want to make use of entities in my <h:selectOneMenu>? It should for JSF be possible to just extract the selected item from the list of available items. If I really have to use a converter, what is the practical way of doing it? So far I came up to this:
Create a Converter implementation for the entity.
Overriding the getAsString(). I think I don't need this since the label property of the SelectItem will be used to display the dropdown option label.
Overriding the getAsObject(). I think this will be used to return the correct SelectItem or entity depending on the type of the selected field defined in the managed bean.
The getAsObject() confuses me. What is the efficient way to do this? Having the string value, how do I get the associated entity object? Should I query the entity object from the service object based on the string value and return the entity? Or perhaps somehow I can access the list of the entities that form the selection items, loop them to find the correct entity, and return the entity?
What is the normal approach of this?
Introduction
JSF generates HTML. HTML is in Java terms basically one large String. To represent Java objects in HTML, they have to be converted to String. Also, when a HTML form is submitted, the submitted values are treated as String in the HTTP request parameters. Under the covers, JSF extracts them from the HttpServletRequest#getParameter() which returns String.
To convert between a non-standard Java object (i.e. not a String, Number or Boolean for which EL has builtin conversions, or Date/LocalDate/ZonedDateTime for which JSF provides builtin <f:convertDateTime> tag), you really have to supply a custom Converter. The SelectItem has no special purpose at all. It's just a leftover from JSF 1.x when it wasn't possible to supply e.g. List<Warehouse> directly to <f:selectItems>. It has also no special treatment as to labels and conversion.
getAsString()
You need to implement getAsString() method in such way that the desired Java object is been represented in an unique String representation which can be used as HTTP request parameter. Normally, the technical ID (the database primary key) is used here.
public String getAsString(FacesContext context, UIComponent component, Object modelValue) {
if (modelValue == null) {
return ""; // Never return null here!
}
if (modelValue instanceof Warehouse) {
return String.valueOf(((Warehouse) modelValue).getId());
} else {
throw new ConverterException(new FacesMessage(modelValue + " is not a valid Warehouse"));
}
}
Note that returning an empty string in case of a null/empty model value is significant and required by the javadoc:
Returns: a zero-length String if value is null, otherwise the result of the conversion
Otherwise the generated <option> will not have a value attribute and by default send the item label back into getAsObject(). See also Using a "Please select" f:selectItem with null/empty value inside a p:selectOneMenu.
getAsObject()
You need to implement getAsObject() in such way that exactly that String representation as returned by getAsString() can be converted back to exactly the same Java object specified as modelValue in getAsString().
public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
if (submittedValue == null || submittedValue.isEmpty()) {
return null;
}
try {
return warehouseService.find(Long.valueOf(submittedValue));
} catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage(submittedValue + " is not a valid Warehouse ID"), e);
}
}
In other words, you must be technically able to pass back the returned object as modelValue argument of getAsString() and then pass back the obtained string as submittedValue argument of getAsObject() in an infinite loop.
Usage
Finally just annotate the Converter with #FacesConverter to hook on the object type in question, JSF will then automatically take care of conversion when Warehouse type ever comes into the picture:
#FacesConverter(forClass=Warehouse.class)
That was the "canonical" JSF approach. It's after all not very effective as it could indeed also just have grabbed the item from the <f:selectItems>. But the most important point of a Converter is that it returns an unique String representation, so that the Java object could be identified by a simple String suitable for passing around in HTTP and HTML.
Generic converter based on toString()
JSF utility library OmniFaces has a SelectItemsConverter which works based on toString() outcome of the entity. This way you do not need to fiddle with getAsObject() and expensive business/database operations anymore. For some concrete use examples, see also the showcase.
To use it, just register it as below:
<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
And make sure that the toString() of your Warehouse entity returns an unique representation of the entity. You could for instance directly return the ID:
#Override
public String toString() {
return String.valueOf(id);
}
Or something more readable/reusable:
#Override
public String toString() {
return "Warehouse[id=" + id + "]";
}
See also:
How to populate options of h:selectOneMenu from database?
Generic JSF entity converter - so that you don't need to write a converter for every entity.
Using enums in JSF selectitems - enums needs to be treated a bit differently
How to inject #EJB, #PersistenceContext, #Inject, #Autowired, etc in #FacesConverter?
Unrelated to the problem, since JSF 2.0 it's not explicitly required anymore to have a List<SelectItem> as <f:selectItem> value. Just a List<Warehouse> would also suffice.
<h:selectOneMenu value="#{bean.selectedWarehouse}">
<f:selectItem itemLabel="Choose one .." itemValue="#{null}" />
<f:selectItems value="#{bean.availableWarehouses}" var="warehouse"
itemLabel="#{warehouse.name}" itemValue="#{warehouse}" />
</h:selectOneMenu>
private Warehouse selectedWarehouse;
private List<Warehouse> availableWarehouses;
Example of JSF generic converter with ABaseEntity and identifier:
ABaseEntity.java
public abstract class ABaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
public abstract Long getIdentifier();
}
SelectItemToEntityConverter.java
#FacesConverter(value = "SelectItemToEntityConverter")
public class SelectItemToEntityConverter implements Converter {
#Override
public Object getAsObject(FacesContext ctx, UIComponent comp, String value) {
Object o = null;
if (!(value == null || value.isEmpty())) {
o = this.getSelectedItemAsEntity(comp, value);
}
return o;
}
#Override
public String getAsString(FacesContext ctx, UIComponent comp, Object value) {
String s = "";
if (value != null) {
s = ((ABaseEntity) value).getIdentifier().toString();
}
return s;
}
private ABaseEntity getSelectedItemAsEntity(UIComponent comp, String value) {
ABaseEntity item = null;
List<ABaseEntity> selectItems = null;
for (UIComponent uic : comp.getChildren()) {
if (uic instanceof UISelectItems) {
Long itemId = Long.valueOf(value);
selectItems = (List<ABaseEntity>) ((UISelectItems) uic).getValue();
if (itemId != null && selectItems != null && !selectItems.isEmpty()) {
Predicate<ABaseEntity> predicate = i -> i.getIdentifier().equals(itemId);
item = selectItems.stream().filter(predicate).findFirst().orElse(null);
}
}
}
return item;
}
}
And usage:
<p:selectOneMenu id="somItems" value="#{exampleBean.selectedItem}" converter="SelectItemToEntityConverter">
<f:selectItem itemLabel="< select item >" itemValue="#{null}"/>
<f:selectItems value="#{exampleBean.availableItems}" var="item" itemLabel="${item.identifier}" itemValue="#{item}"/>
</p:selectOneMenu>

selectManyMenu Converter basics [duplicate]

I have problems understanding how to use selection in JSF 2 with POJO/entity effectively. For example, I'm trying to select a Warehouse entity via the below dropdown:
<h:selectOneMenu value="#{bean.selectedWarehouse}">
<f:selectItem itemLabel="Choose one .." itemValue="#{null}" />
<f:selectItems value="#{bean.availableWarehouses}" />
</h:selectOneMenu>
And the below managed bean:
#Named
#ViewScoped
public class Bean {
private Warehouse selectedWarehouse;
private List<SelectItem> availableWarehouses;
// ...
#PostConstruct
public void init() {
// ...
availableWarehouses = new ArrayList<>();
for (Warehouse warehouse : warehouseService.listAll()) {
availableWarehouses.add(new SelectItem(warehouse, warehouse.getName()));
}
}
// ...
}
Notice that I use the whole Warehouse entity as the value of SelectItem.
When I submit the form, this fails with the following faces message:
Conversion Error setting value 'com.example.Warehouse#cafebabe' for 'null Converter'.
I was hoping that JSF could just set the correct Warehouse object to my managed bean when I wrap it in a SelectItem. Wrapping my entity inside the SelectItem was meant to skip creating a Converter for my entity.
Do I really have to use a Converter whenever I want to make use of entities in my <h:selectOneMenu>? It should for JSF be possible to just extract the selected item from the list of available items. If I really have to use a converter, what is the practical way of doing it? So far I came up to this:
Create a Converter implementation for the entity.
Overriding the getAsString(). I think I don't need this since the label property of the SelectItem will be used to display the dropdown option label.
Overriding the getAsObject(). I think this will be used to return the correct SelectItem or entity depending on the type of the selected field defined in the managed bean.
The getAsObject() confuses me. What is the efficient way to do this? Having the string value, how do I get the associated entity object? Should I query the entity object from the service object based on the string value and return the entity? Or perhaps somehow I can access the list of the entities that form the selection items, loop them to find the correct entity, and return the entity?
What is the normal approach of this?
Introduction
JSF generates HTML. HTML is in Java terms basically one large String. To represent Java objects in HTML, they have to be converted to String. Also, when a HTML form is submitted, the submitted values are treated as String in the HTTP request parameters. Under the covers, JSF extracts them from the HttpServletRequest#getParameter() which returns String.
To convert between a non-standard Java object (i.e. not a String, Number or Boolean for which EL has builtin conversions, or Date/LocalDate/ZonedDateTime for which JSF provides builtin <f:convertDateTime> tag), you really have to supply a custom Converter. The SelectItem has no special purpose at all. It's just a leftover from JSF 1.x when it wasn't possible to supply e.g. List<Warehouse> directly to <f:selectItems>. It has also no special treatment as to labels and conversion.
getAsString()
You need to implement getAsString() method in such way that the desired Java object is been represented in an unique String representation which can be used as HTTP request parameter. Normally, the technical ID (the database primary key) is used here.
public String getAsString(FacesContext context, UIComponent component, Object modelValue) {
if (modelValue == null) {
return ""; // Never return null here!
}
if (modelValue instanceof Warehouse) {
return String.valueOf(((Warehouse) modelValue).getId());
} else {
throw new ConverterException(new FacesMessage(modelValue + " is not a valid Warehouse"));
}
}
Note that returning an empty string in case of a null/empty model value is significant and required by the javadoc:
Returns: a zero-length String if value is null, otherwise the result of the conversion
Otherwise the generated <option> will not have a value attribute and by default send the item label back into getAsObject(). See also Using a "Please select" f:selectItem with null/empty value inside a p:selectOneMenu.
getAsObject()
You need to implement getAsObject() in such way that exactly that String representation as returned by getAsString() can be converted back to exactly the same Java object specified as modelValue in getAsString().
public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
if (submittedValue == null || submittedValue.isEmpty()) {
return null;
}
try {
return warehouseService.find(Long.valueOf(submittedValue));
} catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage(submittedValue + " is not a valid Warehouse ID"), e);
}
}
In other words, you must be technically able to pass back the returned object as modelValue argument of getAsString() and then pass back the obtained string as submittedValue argument of getAsObject() in an infinite loop.
Usage
Finally just annotate the Converter with #FacesConverter to hook on the object type in question, JSF will then automatically take care of conversion when Warehouse type ever comes into the picture:
#FacesConverter(forClass=Warehouse.class)
That was the "canonical" JSF approach. It's after all not very effective as it could indeed also just have grabbed the item from the <f:selectItems>. But the most important point of a Converter is that it returns an unique String representation, so that the Java object could be identified by a simple String suitable for passing around in HTTP and HTML.
Generic converter based on toString()
JSF utility library OmniFaces has a SelectItemsConverter which works based on toString() outcome of the entity. This way you do not need to fiddle with getAsObject() and expensive business/database operations anymore. For some concrete use examples, see also the showcase.
To use it, just register it as below:
<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
And make sure that the toString() of your Warehouse entity returns an unique representation of the entity. You could for instance directly return the ID:
#Override
public String toString() {
return String.valueOf(id);
}
Or something more readable/reusable:
#Override
public String toString() {
return "Warehouse[id=" + id + "]";
}
See also:
How to populate options of h:selectOneMenu from database?
Generic JSF entity converter - so that you don't need to write a converter for every entity.
Using enums in JSF selectitems - enums needs to be treated a bit differently
How to inject #EJB, #PersistenceContext, #Inject, #Autowired, etc in #FacesConverter?
Unrelated to the problem, since JSF 2.0 it's not explicitly required anymore to have a List<SelectItem> as <f:selectItem> value. Just a List<Warehouse> would also suffice.
<h:selectOneMenu value="#{bean.selectedWarehouse}">
<f:selectItem itemLabel="Choose one .." itemValue="#{null}" />
<f:selectItems value="#{bean.availableWarehouses}" var="warehouse"
itemLabel="#{warehouse.name}" itemValue="#{warehouse}" />
</h:selectOneMenu>
private Warehouse selectedWarehouse;
private List<Warehouse> availableWarehouses;
Example of JSF generic converter with ABaseEntity and identifier:
ABaseEntity.java
public abstract class ABaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
public abstract Long getIdentifier();
}
SelectItemToEntityConverter.java
#FacesConverter(value = "SelectItemToEntityConverter")
public class SelectItemToEntityConverter implements Converter {
#Override
public Object getAsObject(FacesContext ctx, UIComponent comp, String value) {
Object o = null;
if (!(value == null || value.isEmpty())) {
o = this.getSelectedItemAsEntity(comp, value);
}
return o;
}
#Override
public String getAsString(FacesContext ctx, UIComponent comp, Object value) {
String s = "";
if (value != null) {
s = ((ABaseEntity) value).getIdentifier().toString();
}
return s;
}
private ABaseEntity getSelectedItemAsEntity(UIComponent comp, String value) {
ABaseEntity item = null;
List<ABaseEntity> selectItems = null;
for (UIComponent uic : comp.getChildren()) {
if (uic instanceof UISelectItems) {
Long itemId = Long.valueOf(value);
selectItems = (List<ABaseEntity>) ((UISelectItems) uic).getValue();
if (itemId != null && selectItems != null && !selectItems.isEmpty()) {
Predicate<ABaseEntity> predicate = i -> i.getIdentifier().equals(itemId);
item = selectItems.stream().filter(predicate).findFirst().orElse(null);
}
}
}
return item;
}
}
And usage:
<p:selectOneMenu id="somItems" value="#{exampleBean.selectedItem}" converter="SelectItemToEntityConverter">
<f:selectItem itemLabel="< select item >" itemValue="#{null}"/>
<f:selectItems value="#{exampleBean.availableItems}" var="item" itemLabel="${item.identifier}" itemValue="#{item}"/>
</p:selectOneMenu>

Resources