Friday, September 7, 2007

Objects in h:selectOneMenu

WARNING - OUTDATED CONTENT!

This article is targeted on JSF 1.2. For JSF 2.0, using objects in UISelectOne and UISelectMany components can be approached much more elegantly with help of OmniFaces SelectItemsConverter without the need to write a custom converter.

Introduction

A HTML response is in Object Oriented perspective nothing less or more than one big String value (technically: a long character array). Non-String-typed Java Objects are forced to their String representation using Object#toString() when they are about to be written to the HTML response. That's why using custom Object types in a UISelectOne or UISelectMany component, for example h:selectOneMenu, can drive unaware JSF developers nuts. If you gently have attached a <h:message /> to the component for error messages, or added the <h:messages /> tag to the page for debugging purposes, then you will likely get the following error message:

Conversion Error setting value 'mypackage.Foo@1234567' for 'null Converter'.

That roughly means that JSF cannot convert the given String value "mypackage.Foo@1234567" (which is just the String representation of the Object, obtained by Object#toString()) to the Object type which is expected by the valuebinding of the component, e.g. mypackage.Foo. The message also indicates that JSF couldn't find a suitable converter for it, pointing to the null ID in the 'null Converter' message part. Generally this will only occur if those objects are not of a String type and JSF does not have a built-in converter for it as well. That's why, next to plain String values, for example the types of the Number superclass just works in the h:selectOneMenu. At least in the newer builds of JSF, the 1.1_02 and 1.2_02 or later, due to some coerce bugs with Number types in SelectItem in the older builds.

There are two general solutions for this conversion problem: 1) implement javax.faces.convert.Converter and write logic which converts between String (or Number) and the desired Object. 2) maintain a backing map with an unique String (or Number) representation as key and the appropriate Object as value. Both approaches will be descibed here in detail.

Back to top

Using a Converter

Using a Converter is fairly simple. You just need to write some logic how to Convert between String and the desired Object type. Instead of String you can also use any Number type, for example Long, because JSF already has built-in converters for it.

Let's start with a relevant part of the JSF page:

<h:form>
    <h:selectOneMenu value="#{myBean.selectedItem}">
        <f:selectItems value="#{myBean.selectItems}" />
        <f:converter converterId="fooConverter" />
    </h:selectOneMenu>
    <h:commandButton value="submit" action="#{myBean.action}" />
    <h:messages />
</h:form>

Note the f:converter facet. The value of its converterId attribute must match with one of the converters as definied in the faces-config.xml. The faces-config.xml example will be shown later in this paragraph.

And here is the appropriate backing bean MyBean:

package mypackage;

import java.util.ArrayList;
import java.util.List;

import javax.faces.model.SelectItem;

public class MyBean {

    // Init ---------------------------------------------------------------------------------------

    private static FooDAO fooDAO = new FooDAO();
    private List<SelectItem> selectItems;
    private Foo selectedItem;

    {
        fillSelectItems();
    }

    // Actions ------------------------------------------------------------------------------------

    public void action() {
        System.out.println("Selected Foo item: " + selectedItem);
    }

    // Getters ------------------------------------------------------------------------------------

    public List<SelectItem> getSelectItems() {
        return selectItems;
    }

    public Foo getSelectedItem() {
        return selectedItem;
    }

    // Setters ------------------------------------------------------------------------------------

    public void setSelectedItem(Foo selectedItem) {
        this.selectedItem = selectedItem;
    }

    // Helpers ------------------------------------------------------------------------------------

    private void fillSelectItems() {
        selectItems = new ArrayList<SelectItem>();
        for (Foo foo : fooDAO.list()) {
            selectItems.add(new SelectItem(foo, foo.getValue()));
        }
    }

}

This is how the Foo object type look like. It is actually a random Data Transfer Object (DTO). Please note the Object#equals() implementation. This is very important for JSF. After conversion, it will compare the selected item against the items in the list. As the Object#equals() also require Object#hashCode(), this is implemented as well.

package mypackage;

public class Foo {

    // Init ---------------------------------------------------------------------------------------

    private String key; // You can also use any Number type, e.g. Long.
    private String value;

    // Constructors -------------------------------------------------------------------------------

    public Foo() {
        // Default constructor, keep alive.
    }

    public Foo(String key, String value) {
        this.key = key;
        this.value = value;
    }

    // Getters ------------------------------------------------------------------------------------

    public String getKey() {
        return key;
    }

    public String getValue() {
        return value;
    }

    // Setters ------------------------------------------------------------------------------------

    public void setKey(String key) {
        this.key = key;
    }

    public void setValue(String value) {
        this.value = value;
    }

    // Helpers ------------------------------------------------------------------------------------

    // This must return true for another Foo object with same key/id.
    public boolean equals(Object other) {
        return other instanceof Foo && (key != null) ? key.equals(((Foo) other).key) : (other == this);
    }

    // This must return the same hashcode for every Foo object with the same key.
    public int hashCode() {
        return key != null ? this.getClass().hashCode() + key.hashCode() : super.hashCode();
    }

    // Override Object#toString() so that it returns a human readable String representation.
    // It is not required by the Converter or so, it just pleases the reading in the logs.
    public String toString() {
        return "Foo[" + key + "," + value + "]";
    }

}

And here is a fake DAO which maintains the Foo DTO's. Take note that the database is simulated by a static backing map, this doesn't need to occur in real life. It should actually be mapped to a database or maybe even configuration files or so. For more information about the DAO pattern, check this article: DAO tutorial - the data layer.

package mypackage;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class FooDAO {

    // Init ---------------------------------------------------------------------------------------

    private static Map<String, Foo> fooMap;

    static {
        loadFooMap(); // Preload the fake database.
    }

    // Actions ------------------------------------------------------------------------------------

    public Foo find(String key) {
        return fooMap.get(key);
    }

    public List<Foo> list() {
        return new ArrayList<Foo>(fooMap.values());
    }

    public Map<String, Foo> map() {
        return fooMap;
    }

    // Helpers ------------------------------------------------------------------------------------

    private static void loadFooMap() {
        // This is just a fake database. We're using LinkedHashMap as it maintains the ordering.
        fooMap = new LinkedHashMap<String, Foo>();
        fooMap.put("fooKey1", new Foo("fooKey1", "fooValue1"));
        fooMap.put("fooKey2", new Foo("fooKey2", "fooValue2"));
        fooMap.put("fooKey3", new Foo("fooKey3", "fooValue3"));
    }

}

Finally here is the long-awaiting FooConverter which can be used in JSF components. It converts from Foo to String and vice versa. You can attach it to almost any HTML input or output component using the converter attribute or using the f:converter facet.

package mypackage;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;

public class FooConverter implements Converter {

    // Init ---------------------------------------------------------------------------------------
    
    private static FooDAO fooDAO = new FooDAO();

    // Actions ------------------------------------------------------------------------------------
    
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        // Convert the unique String representation of Foo to the actual Foo object.
        return fooDAO.find(value);
    }

    public String getAsString(FacesContext context, UIComponent component, Object value) {
        // Convert the Foo object to its unique String representation.
        return ((Foo) value).getKey();
    }

}

Take care with runtime exceptions as NullPointerException, ClassCastException and maybe some exceptions which can be thrown by your DAO. Those have to be checked and/or caught and should be thrown as a new ConverterException with the appropriate message which would be shown in the attached h:message(s) tag.

The MyBean and the FooConverter are definied in the faces-config.xml as follows:

<converter>
    <converter-id>fooConverter</converter-id>
    <converter-class>mypackage.FooConverter</converter-class>
</converter>
<managed-bean>
    <managed-bean-name>myBean</managed-bean-name>
    <managed-bean-class>mypackage.MyBean</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
</managed-bean>

You can however also use converter-for-class instead of converter-id so that JSF will always use the specified converter class for the given class. This way you don't need to specify the f:converter in your JSF code.

<converter>
    <converter-for-class>mypackage.Foo</converter-for-class>
    <converter-class>mypackage.FooConverter</converter-class>
</converter>

That's all, folks!

Back to top

Using a backing Map

You can also decide to use a so-called backing Map to maintain String-Object pairs and convert against it in the backing bean logic. The String keys can be used in the view layer (JSF pages) and the Object values can be used in the business and data layers (backing beans and DAO's). You can also use Number-Object pairs however.

The relevant part of the JSF page is almost the same as in the case of using a converter, only the f:converter tag is removed:

<h:form>
    <h:selectOneMenu value="#{myBean.selectedItem}">
        <f:selectItems value="#{myBean.selectItems}" />
    </h:selectOneMenu>
    <h:commandButton value="submit" action="#{myBean.action}" />
    <h:messages />
</h:form>

And here is the appropriate backing bean MyBean, it has a static Map of String-Foo pairs. It's your choice how you would load/maintain it, this is just a basic example. Take note that the selectedItem is now a String instead of Foo.

package mypackage;

import java.util.ArrayList;
import java.util.List;

import javax.faces.model.SelectItem;

public class MyBean {

    // Init ---------------------------------------------------------------------------------------

    private static Map<String, Foo> fooMap = new FooDAO().map();
    private List<SelectItem> selectItems;
    private String selectedItem; // You can also use any Number type, e.g. Long.

    {
        fillSelectItems();
    }

    // Actions ------------------------------------------------------------------------------------

    public void action() {
        System.out.println("Selected Foo item: " + fooMap.get(selectedItem));
    }

    // Getters ------------------------------------------------------------------------------------

    public List<SelectItem> getSelectItems() {
        return selectItems;
    }

    public String getSelectedItem() {
        return selectedItem;
    }

    // Setters ------------------------------------------------------------------------------------

    public void setSelectedItem(String selectedItem) {
        this.selectedItem = selectedItem;
    }

    // Helpers ------------------------------------------------------------------------------------

    private void fillSelectItems() {
        selectItems = new ArrayList<SelectItem>();
        for (Foo foo : fooMap.values()) {
            selectItems.add(new SelectItem(foo.getKey(), foo.getValue()));
        }
    }

}

That's it! You can just reuse the Foo DTO, the FooDAO DAO and the faces-config.xml snippet from the Using a Converter paragraph here above. No FooConverter is needed in here and you can also safely remove it from the faces-config.xml.

Back to top

Copyright - There is no copyright on the code. You can copy, change and distribute it freely. Just mentioning this site should be fair.

(C) September 2007, BalusC

83 comments:

Alex said...

Thanks for an excellent post.
BTW, if you declare
Collection SelectItem selectItems
instead of
List SelectItem selectItems
and try to populate it with HashSets, you'll be facing a 500 error with no sensible exception. That's what I did ;).
Can't get the reason why.

Bauke Scholtz said...

The root cause of the exception should be available in the server log. At least, the f:selectItems expects a List or an array of SelectItem objects. A Set is indeed not going to work.

Alex said...

@balusc
Yes, you are right. What was misleading is that in Core JSF 2nd ed. they write that a Collection of SelectItems is supported. Probably I'm getting smth wrong.
BTW, as it's very likely that there will be only one converter per class, to use
(wish it was possible to post tags here)
--
converter
converter-for-class
converter-class
converter
--
tags inside faces-config. Now you are free from explicitly specifying converter in the code.
Now, there's an interesting task I'm beating my brains out on.
In a dataTable, how would one represent a List of objects as selectItems?
If I get to a solution, I'll post it here.

Julien said...

Excellent article as usual!! I am just wondering whether you plan on publishing the collection of your articles as a pdf or a book. If so I am interested. Please let us know.

Unknown said...

I normally do not leave comments to blogs. However I feel this blog has save me more time and provided better examples than all the other blogs combined. I just want to say thanks and keep up the great work.

torres said...

hi balusc,
hats off to u .i am relatively new to jsf. i have a question to you.i have a problem with this selectonemenubox.
I created a new ListSelectItem .I created a for(enhanced) loop . The list which i referred in for loop was a List of type Company.i add this list with my new ListSelectItems.it gets add to it but when i run jsf there is an error thrown saying"Value binding '#{sprUserHandler.sprUserBean.companyList}' of UISelectItem does not reference an Object of type SelectItem".
but if i print List SelectItem by converting it with toString ,its showing me an object of type SelectItem "javax.faces.model.SelectItem@1ed2bbd" . what might the problem

Muraliz said...

Hey Balusc,

Thanks for posting some wonderful articles. I have this problem which keeps coming again and again. This time, I have to do this way or else, there is no going back.

The requirement is pretty straight forward: An admin of the application can create at run time a module, where in he would configure different UI/form element attributes.

e.g. Module A: 2 dropdowns, 1 radio element block, 4 text boxes;
Module B: 1 dropdown; 3 text boxes.

so on and so forth.

Depending upon the access set for these modules, a user may get to see these modules.

The solution which I have thought of [of course, after reading couple of java sun forums as well] is to dynamically populate a HashMap with keys to these UI/form elements for a module and then, dynamically construct the user access page.

This is working absolutely fine. The problem is when I am trying to capture the submitted values. The HashMap is unable to post the set values of the UI elements.

Can you please help? Do you see any flaws in this approach?

gaferoz said...

Hello BalusC. I have implemented a SelectOneMenu based on your coding in this example. However, I'm trying to populate the SelectItems list from a DAO database access. The DAO code gets the list from a Spring JPA access to the database, which works beautifully and gets the data from it when running a JUnit test using AbstractJpaTests.

A different thing is when i try to populate the SelectOneMenu list using the DAO access. In this case I use a similar code like yours; I inject a DAO bean into the JSF controller managed-bean using an initialiser block like your {fillSelectItems} block. However, it throws a NullPointerException, and when debugging, Eclipse debug shows the DAO object variable is null, say, the controller instance variables have not been injected with the DAO bean reference.

¿Do you know why this happens? I've been trying to solve this problem and I'm almost flat on it.

Bauke Scholtz said...

Injecting properties in a bean would only happen after the bean is been constructed and initialized. So you need to fill the menu items right after the injection. You can use lazy loading in the setter of the DAO for that. Or if you're using JSF 1.2, then you can use the @PostConstruct annotation for that, set it on the method which fills the menu items.

sidra said...

Hello, I populate a selectOneMenu with a list of strings from database, the thing is that forward I need the id of the object selected..please help me

Anonymous said...

hi balusc
Good post,
I have one question... I case of selectonemenu with java.util.Date objects How the converter is selected? Do I have to mention teh converter like above or do i have to write conveter?

Also how should I populate selectitems with ? is this correct SelectItem(new Date()) ?

Bauke Scholtz said...

You need to convert between Date and String. The JSF already provides you the f:convertDateTime for that. If this is unsatisfactory, just implement your own converter.

lime said...

hi balusc,

Great work! I have it working beautifully. I just have one quick question though.

I have a selectOneRadio that uses a WireType object. I don't want to default that radio but if it's not selected I get a validator error saying 'summary=Validation Error: Value is not valid' I'm guessing this has something to do with a null somewhere. Do you know how I could basically make the converter ignore it if nothing is selected???

Thanks

Bauke Scholtz said...

If you take this article as example and you only replace h:selectOneMenu by h:selectOneRadio, it should work flawlessly either.

In converter's view, the getAsObject() of your converter should return null when nothing is selected.

lime said...

The problem is that it doesn't even get to the getAsObject() when I don't select anything. I'm debugging it right now and I see it calling WireType.equals() four times even though I have two options, one time the "this" is null and it compares it against the two options, the next time "this" is one of the options and the obj is null so that method never returns true, after those method calls is when I see it adding a message to the Faces Context. Any ideas?

Bauke Scholtz said...

You're right, the converter is not to be called when nothing is selected. The equals shouldn't be called either. Which JSF implementation/version are you using?

Also try reproducing the issue by copypasting the exact code in this article and only change the h:selectOneMenu to h:selectOneRadio.

lime said...

It's an ibm-jsf implementation. equals() is definetely getting called when I click on a submit button, from what I can tell on the stack trace it's trying to match the selected value to something in the list of SelectItems but no item is selected so it's throwing that validation message. I tried copying and pasting and just changing the names of the values and it's doing the same thing. I also just tried a custom validator that does nothing to see if that would work but it's still going through the HtmlSelectOneRadio .matchValue() method. Maybe I will just have to preselect one of them no matter what....

Bauke Scholtz said...

IBM doesn't have a JSF implementation, but only a component library (the Faces Client Framework, with the 'hx' taglib). Websphere and on ships by default with the early builds of Sun RI 1.0 or 1.1, depending on WS version. In both cases, consider upgrading to the latest 1.1, the 1.1._02 which is available at here. (Re)place the jsf-api.jar and jsf-impl.jar in the WEB-INF/lib of the project.

lime said...

I just thought it was an IBM implementation because when I created this project in RAD 7 it automatically added jsf-ibm.jar to the WEB-INF/lib so I was just going off of that. I've been googling around and seen other people with this problem so I wonder if a new version will even fix it. I'm pretty limited to upgrading the jar files anyways so I might have to default it no matter what and hope the business doesn't care whether it's preselected or not. I thought a customer validator would work but apparently that doesn't keep it from using the matchValue() method. Thanks for all your help!

Bauke Scholtz said...

The jsf-ibm.jar is the IBM component library. Your problem is related to the actual JSF implementation, which exist of the jsf-api.jar and jsf-impl.jar. If you extract those files and read the manifest file you should see the implementation brand and version. Big chance that it is the Sun RI 1.1 or very maybe 1.1_01. Upgrading to RI 1.1_02 is really worth the effort. The 1.1 is from 2004 and the 1.1_02 is from 2006 and in those 2 years really many bugfixes are been released. I can tell from experience, I've used Websphere 5.x and 6.x for years.

lime said...

Well it looks like it's the 1.1_02 version anyways.

From the manifest:
Implementation-Title: 'jsf-impl': JavaServer Faces RI
Implementation-Version: 1.1_02-b08
Implementation-Vendor: Sun Microsystems, Inc.

Not sure why it was still breaking, I'm defaulting it now and it's working correctly. Hopefully I don't run into another place where I use a customer converter and don't want it defaulted to something.

Thanks for all your help, also I was looking around your blog and you have tons of great entries!

Anonymous said...

How to call backing bean action on event onchange of selectonemenu option?

Bauke Scholtz said...

Just submit the form during the onchange event.

Hims said...

Excellent post.
I am new to JSF.
Your blog helped me alot.

Thanks Once again
HimSss

J.Naveen said...

Thanks for an excellent post. we are also following the same by using Arraylist for selectItems but only the thing is we are using component binding instead of value binding, here i want to set the selected value with the label not with the key so how can I do that.

Bauke Scholtz said...

Don't use a label-value pair in SelectItem, but only use label as value.

J.Naveen said...

thanks for your immediate reply, but in my project we use key-lable pair in the business logic the key also plays huge role thats why i can't change my structure but any way I wrote a method to get the f:selectItems and iterating to get the lable and setting that

Bossie said...

Hey there BalusC,

First of all, again a very interesting read! Informative, to the point and not cluttered with "I'm so smart I use 25 paragraphs to make my point" text :)

Do you have any experience with Seam and using Custom Converters?
As far as I know it's more or less the same manner of operation, though the instantiating of components is done through annotations rather then through faces-config.xml

I'm kinda hoping you have some experience in this as well, as I keep getting an error stating that my customConverter cannot be found.

Any thoughts?

Bauke Scholtz said...

Unfortunately not, no. I checked this document, but I can't seem to find anything about annotated converters. Try posting this question at their own forum. Good luck.

Matt said...

Thanks for the post. It is really helpful. From what I can tell this should work for other tags as well such as h:selectOneRadio. Has anybody tried it and had it work sucessfully? I tried with radio buttons and had no luck. It seems to call the converter and properly convert the objects to strings (ID's), but the correct previously selected option is not checked when I go to the page. If I change only h:selectOneRadio to h:selectOneMenu the correct option is chosen in the list. Any suggestions???

kapil said...

Thanks for the very informative article. One thing that is still unclear to me is how can I create dependent select boxed where change in value in one combo changes the list of values in other combo. It will be very helpful if you provide some information on it.

Bauke Scholtz said...

Click the "SelectOneMenu" label/tag of this blog for more articles.

Unknown said...

Hi BalusC.. Thank you for this post. This has saved me from a major headache ;)

AlexWal said...

Balus,

First Off, I love you man... in a idol - idol worshipper type way.

Second, is there any way I can send you my code so you take a look at it. I've followed every step of your article but I'm still getting the "Conversion Error setting value '' for 'null Converter'" error. I can send you everything you need, view, model, DAO, DTO, faces-config.xml, everything. Just create a directory src/example, drop em in and run em. I'd copy and paste them here but the number of characters exceeds the blog limit.

I can show you some right now though:

whoops, no I can't, not even the Java, think the generics get interpreted as html.

Well, anyway, if there's a way I can send you my files I'd really appreciate it.

Thanks

Bauke Scholtz said...

I recommend to start with an unchanged copypaste of the article's code into your playground. This should work. Then build on that further.

stunning said...

Thanks BalusC, but what's a "playground"?

stunning said...

Oh, sorry, I'm a bit burned out today, I've got your code verbatim in my JDeveloper 10.1.3.3 playground or sandbox, all the files are in one directory called example and I'm totally psyched, but when I hit the "Add" button to add a row I get the null converter error. That's why I'm wanting to let you look at my files and try to see what the problem is. I email you a war, it's like 2 mb, I'm not at work so I don't know the exact size.

Thanks

Bauke Scholtz said...

I am not sure what you're talking about with the 'Add' button. I suggest you to start a topic with an SSCCE at the JSF forum at Sun Developer Network.

Unknown said...

I am trying to populate a jsf dropdown list with values that contain Dutch characters. I'm using java 1.4 and JSF 1.1.4 Please help, it's driving me crazy!

Bauke Scholtz said...

Prejith, this more sounds like that you have just a character encoding problem. In that case, make sure everything is set to UTF-8. Also see this article: Unicode - How to get characters right?.

Unknown said...

Very good explanation, answered my questions perfectly.

arnljot said...

Thank you for a very detailed example.

I tried to use the same approach for a h:selectManyCheckbox component.

The converter approach did not work. When I try it with a backing bean having a get/setter pair for List[SelectItem] Spring faces with javax.faces v1.12_08 throws out an error that the value is invalid.

If I change the get/setter pair to SelectItem[] I get the null converter error which you mention in the beginning of your post.

Going with the Map approach works flawlessly however.

When I tried the converter approach, I tried registering the converter with converter-for-class. If murphys law is to be trusted, maybe that one deviation from your example is to blame? However I've seen it work demonstrated by other bloggers..

Bauke Scholtz said...

The "the value is invalid" error can be caused by:

1) f:selectItems list is empty.
2) equals() returned false for any item in f:selectItems list.

arnljot said...

During debugging I checked that the selectItems list was populated. It has several values. So it could be that the equals function doesn't behave as expected.

One question, during post(form submit), should I see the converters getAsObject method fire? It doesn't atm when using the converter approach.

I see from sun developer forum that you suggested to another user a "polluted classpath".

My classpath contains maven artifacts javax.faces:jsf-impl:1.2_08 (quoted wrong version in previous post), javax.faces:jsf-api:1.2_08 and com.sun.facelets:jsf-facelets:1.1.15.B1

Further more I'm using spring-webflow with it's spring-faces integration to the jsf implementation I mentioned.

The validation error happens in the validation phase, and inside the javax.faces:jsf-impl classes.

I'll take another look at my equals code, but it seems solid to me:


public boolean equals(Object o) {
if(o==null) {
return false;
}

if(o == this) {
return true;
}

if(!(o instanceof InnsamlingsMetode)) {
return false;
}

InnsamlingsMetode other = (InnsamlingsMetode) o;

return new EqualsBuilder().append(id, other.id).isEquals();
}


and:

public int hashCode() {
return new HashCodeBuilder().append(id).toHashCode();
}

arnljot said...

Just hit me that I'm delegating some responsability for the id to another object.

That id object also seems good to me.

public boolean equals(Object o) {
if(o == null) {
return false;
}

if(o == this) {
return true;
}

if(!(o instanceof InnsamlingsMetodeId)) {
return false;
}

InnsamlingsMetodeId other = (InnsamlingsMetodeId) o;

return new EqualsBuilder().append(innsamlingMetode, other.innsamlingMetode).append(opprettetDato, other.opprettetDato).isEquals();
}

public int hashCode() {
return new HashCodeBuilder().append(innsamlingMetode).append(opprettetDato).toHashCode();
}

Fernando Giorgetti said...

Thanks for the post! It has a comprehensive demonstration of the selectOneMenu UI. As said, if you don't pay attention to a few details, you'll gonna freak out.

Anonymous said...

hi,
thanks for the tutorial.
but i do not understand why we must do so much thing just to show an arraylist content :S

there is one more thing i want to ask

when i try to run the example it says me in converter's getAsString method,

"can not cast string to foo object".

what should i do?
thanks

Bauke Scholtz said...

Because you cannot pass other things than String as request parameters. That's just a HTTP limitation. HTTP is not object oriented.

As to your actual problem: the problem lies somewhere else. The value is apparently already a String.

Anonymous said...

hello again,
thanks for this article.

DiceIons said...

Thank you for your post. I was trying to use it my application, but faced with null-pointer exception. I use GlassFish and here my bean class with method that calls from converter and causes exception because entity manager is null

@Stateless
@LocalBean
public class SpecialityDAO {

@PersistenceContext
private EntityManager em;

// used in converter
public Speciality getSpecialityByName(String name) {
try {
Query q = em.createQuery("SELECT s FROM domain.Speciality s WHERE s.name=:name");
q.setParameter("name", name);
Speciality s = (Speciality) q.getSingleResult();
return s;
} catch (Exception e) {
return null;
}
}
...
}

here converter class

public class SpecialityConverter implements Converter {

private SpecialityDAO specialityDAO = new SpecialityDAO();

public Object getAsObject(FacesContext context, UIComponent component, String name) {
return specialityDAO.getSpecialityByName(name);
}

public String getAsString(FacesContext context, UIComponent component, Object object) {
return ((Speciality)object).getName();
}
}

and here web






everything else works well, probably in this case I need to initialize entity manager in some special way, but I don't know how...

Thank you

DiceIons said...

For now solved it in other way, here implementation

public Object getAsObject(FacesContext context, UIComponent component, String name) {
Map mp = context.getExternalContext().getSessionMap();
SpecialityController sc = (SpecialityController)mp.get("speciality");
return sc.getSpecialityByName(name);
}

Shilpa Dahiya said...

Hi,
excellent post again..you make my work easier :)

Could you tell me how can I retrieve both the value and Lable of the selected item, from the h:selectOneMenu item, in the backing bean.

Thanks in advance..

Bauke Scholtz said...

How to retrieve the selected value is already explained. How to retrieve the label is straightforward: it's already there in backing bean, just get it by selected value (though I highly question the need to know about the label).

Mehaboob said...

Hi,

I have a requirement for changing the background of the value in h:SelectOneMenu when the mouse is over the value.I mean the value which the mouse points to should be highLighted i.e if have 10 values in the drop down when my mouse is on the second value in dropdown the value should be highlighted in yellow whereas the others should not be highlighted.
I tried using onmouseover attribute but it jut mess up my logic when mouse is over the dropdown all values are highLighted.

Unknown said...

Hi Balusc,

I am also looking at the same requirement for highlighting as mentioned above.Any help on it would be really great.

Thanks and Regards,
Namita

Bauke Scholtz said...

That's not supported by the HTML `<option>` element. Your best bet is an `<ul&gt` which is mimiced as a dropdown by Javascript.

Asi said...

Hi BalusC,

I want to remove an item in my selectOneMenu, there is an arraylist in my bean that contains list items. How can I remove selected item via a button.
I have already tried to remove selected item from issued array but I could not find the way to reach it.

Is there any way to do that?

Please help me, that is very very important for me,
Best Regards,
Asiye

Thang Pham said...
This comment has been removed by the author.
Thang Pham said...
This comment has been removed by the author.
Thang Pham said...

This is what I have

facilities.add(new SelectItem("This is Test", fac.getName()));

Where facilities is List facilities, and fac is an Entity object. Then my h:selecOneMenu just have

h:selectOneMenu id="facility" value="#{document.facility}"> //In managed bean, facility is type String as well
f:selectItems value="#{document.facilities}"

where document is my managed bean. This give me a Validation Error: Value is not valid. I play around a bit, so I changed the above code to

facilities.add(new SelectItem("", fac.getName()));

and that fix it the error. So making the first argument of the SelectItem an empty string fix the Validation Error, make me thing that I am missing some type of conversion. But since my target object facility in managed bean is type string as well. I am not sure how to fix it. So here is my original code

facilities.add(new SelectItem(fac.getId, fac.getName()));

Do you have any idea how to fix it? I delete the two previous comments because I could not get the html to come out correctly. Srry about that

Monkey said...

you are the best maaaaaaan , thanks a million

Unknown said...

h:selectOneMenu id='valBox'
styleClass='selectOneMenu' title='Values' value='#{calVO.money.dollars}'

f:selectItems value='#{action.moneyMap}'

f:converter converterId='moneyConverter'
h:selectOneMenu

LordFrutos said...

Balus, i most say, you are the best! sincerely i learned a looot from you. im starting with jsf, and for luck i found your blog, i learned a lot. thanks!!!

now i have a question, i made just like you made this example, but it dosent display any item in my h:selectonemenu, i mean its blank.

im using your DAO and DTO form the another tutorial, i bring the data good, i checked already, the variables selecteditem and selectitem are good, but i dont know why its blank my h:selectonemenu, the list(selectItems) are good populated with the values, but still i dont have any idea, (im very stupid by the way).

Thanks in advance for everything!

Unknown said...

I solved, it was stupid mistake of mine, this example works perfectly!!!

Thanks for publishing this things!

Anonymous said...

hi,
a map is used in "using converter" section. is there a way not to use any map only converter. thanks

Bauke Scholtz said...

That map represents a fake database. You should do your database access thing in the `find()` method.

Anonymous said...
This comment has been removed by the author.
Anonymous said...

Hi Balu,
I am using h:selectOneMenu.In this, drop down value is not reseting on seletion of default.It shows previously saved/entered value.Please let me know how to clear/reset it.

Regards
Anwar

Umoh said...
This comment has been removed by the author.
Umoh said...

BalusC to the rescue, once again. :)

Ryan said...
This comment has been removed by the author.
thewolf said...

You are a genius!!!

thewolf said...

You are a genius!!! You saved my day!!

Fize said...

Hi BalusC....great blog!....I hope you can help. I'm trying to do something that should be simple. I have a datatable containing a number of lines. Each line contains a selectonemenu that has a list of selectItems (which represent products with an id, name and category).

I basically want it so that when a user changes the product in the select item, the next outputfield in the table displays the category.

Unfortunately I'm unsure what is the best or easiest way to do this.

Rafael A P Nascimento said...

Hi, BalusC, thanks for the great post

For saving on database purposes it worked well;
but I could not get it working when I get some object from database on editing purposes, i.e., the drop down does not show the current value being edited, it appears blank.

you know what's may be wrong ??

Rita said...

hi,

facing issue in p:selectOneMenu

it's working fine when selectOneMenu is prepopulted,but giving validation error when poopulating on p:ajax call

Daniel Dayrit said...

Thanks dude, using a map backing bean is really a bright idea. use the map keyset for display, then get the value (bean) of that keyset from the map when saving.

haunting said...

Thank you BalC. you're really great. you have been very helpful in all my development work

Unknown said...

Thank you!!!!! im very new to jsf and i have spent all day with this problem, the is a real time saver, please keep up the great work you do!

Unknown said...

Thankss you from Argentina!! You´re a genius!! This has helped me a lot!!

ztb said...

What do you eat to be so genius???
ty.

Unknown said...

Hi,
Please is there any way to add Filter function to the standard JSF SelectOneMenu. I have a large list of objects to be showed in the SelectOneMenu that is why I prefer using native JSF component rather than using Primefaces one. However I am facing a problem with adding filter function to the component. Can you please help in this issue?

Unknown said...

Hi Baluc

Thanks for the great post :)
I'm new to JSF and facing one issue with h:selectOneMenu. i have three selectionItem values(All,Checked, Uncheked).whnever iam changing the value of the dropdown, value changelistener is getting triggered and view is getting updated.
I have to introduce one button that always will set the value of the dropdown to All. as part of button action , Iam creating one UISelectOne and setting the value to All. Actually here model is getting updated. but dropdown selection view is not getting updated. it is still showing the old value.


pls help me to resolve the issue
Thanks in advance.