I'm using <s:convertEntity /> and when I submit the form I get an error message on the page /Value is not a valid option/ — what am I doing wrong?
This commonly asked question on the Seam forum refuses to go away — so lets run through the problem, look at the workarounds and what changes would be needed to JSF to make it go away.
The Background
JSF allows you to specify a converter for any editable value; the converter converts /from/ an Object /to/ a String when rendering the page, and /from/ a String /to/ an Object when submitting a form. JSF comes with some built in converters (e.g. for Date, enums...) or allows you to create a custom converter.
Inside your custom converter you implement getAsString, returning a String, which, when passed to getAsObject on submitting the form, you use to get hold of the Object and return it.
Seam provides <s:convertEntity />, a generic converter which does the job of converting any JPA entity (mapped with annotations or XML, with a simple or composite key). It takes the primary key of the entity, stores it, returns a reference to the location in the key store; when the page is submitted, the key is fetched from the store and used to load the entity.
The Problem
The JSF 1.2 Specification (sections 4.1.15.3 and 4.1.16.3) specify that
...must provide a specialized validate() method which ensures that any decoded value is a valid option (from the nested UISelectItem and UISelectItems children).
In other words, the submitted item must be in the list displayed on the page. As the entity converter loads the selected object from the persistence context when the page is submitted, /the submitted object is not in the displayed list/.
The Workarounds
- Display the list and submit the form inside the same long running conversation (so that the persistence context returns the same object both times). This makes caching the list of selectable items hard.
- Overriding equals() on the entity (which isn't a a great idea).
The Solution
For JSF 2 this validation should be optional/overrideable (as it is everywhere else in JSF). In this case the converter is doing all necessary validation.