MyFaces从1.1.4升级至1.1.8后h:selectOneMenu组件失效问题求助
Hey there, let's work through this validation issue you're hitting after upgrading MyFaces from 1.1.4 to 1.1.8. The core problem you identified—type mismatch between the submitted POJO value and string-based SelectItem values in _SelectItemUtil.matchValue()—is a known behavior change in newer MyFaces 1.x versions. Since you can't upgrade JSF entirely, here are three practical solutions to resolve this:
Solution 1: Return POJO instances in your getSelectItems() method
This is the cleanest approach, aligning with JSF's intended usage for select components. Instead of storing string countryId values in your SelectItem instances, directly use Country POJO objects. This ensures the type matches the #{crud.orgAddress.country} value during validation.
Update your getSelectItems() method like this:
public List<SelectItem> getSelectItems(String daoName) { // Fetch full Country POJO instances from your DAO List<Country> countryList = countryDAOCrud.retrieveAllCountries(); List<SelectItem> selectItems = new ArrayList<>(); for (Country country : countryList) { // Pass the Country object as itemValue, and its name as itemLabel selectItems.add(new SelectItem(country, country.getCountryName())); } return selectItems; }
Note: Double-check that your Country class's equals() and hashCode() methods are correctly implemented (based on countryId or another unique identifier) to ensure proper matching between selected and stored values.
Solution 2: Implement a custom Converter
If you can't modify the getSelectItems() method (e.g., it's used elsewhere with string values), create a JSF Converter to convert between string countryId values and Country POJO instances during validation.
Step 1: Create the Converter class
import javax.faces.application.FacesMessage; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.convert.Converter; import javax.faces.convert.ConverterException; public class CountryConverter implements Converter { // Inject your Country DAO (use dependency injection or fetch via FacesContext) private CountryDAOCrud countryDAOCrud; @Override public Object getAsObject(FacesContext context, UIComponent component, String value) { if (value == null || value.trim().isEmpty()) { return null; } try { Long countryId = Long.parseLong(value); // Fetch the corresponding Country POJO from the database return countryDAOCrud.getCountryById(countryId); } catch (NumberFormatException e) { throw new ConverterException(new FacesMessage("Invalid country ID format")); } } @Override public String getAsString(FacesContext context, UIComponent component, Object value) { if (value == null) { return ""; } if (!(value instanceof Country)) { throw new ConverterException(new FacesMessage("Value is not a valid Country instance")); } // Return the string representation of the Country's ID return String.valueOf(((Country) value).getCountryId()); } // Setter for DAO injection (adjust based on your dependency injection setup) public void setCountryDAOCrud(CountryDAOCrud countryDAOCrud) { this.countryDAOCrud = countryDAOCrud; } }
Step 2: Register the Converter in faces-config.xml
<converter> <converter-id>countryConverter</converter-id> <converter-class>com.yourpackage.CountryConverter</converter-class> </converter>
Step 3: Attach the Converter to your h:selectOneMenu
<h:selectOneMenu id="orgCountry" value="#{crud.orgAddress.country}" converter="countryConverter"> <f:selectItem itemLabel="#{messageResources.dropDownPleaseSelect}" itemValue=""/> <f:selectItem itemLabel="#{crud.usrbld.countryName}" itemValue="#{crud.usrbld.countryId}"/> <f:selectItems value="#{getSelectItems('countryDAOCrud')}"/> <a4j:support id="countryDropDown" event="onchange" ajaxSingle="true" reRender="orgState" oncomplete="updateStateDropdown()"/> </h:selectOneMenu>
Solution 3: Override MyFaces' _SelectItemUtil (Not Recommended)
As a last resort, you could override MyFaces' internal _SelectItemUtil class to restore the 1.1.4 behavior of converting string values to POJOs. However, this is risky because it depends on MyFaces' internal implementation, which may change unexpectedly. Only consider this if the first two solutions aren't feasible.
内容的提问来源于stack exchange,提问作者sneha sv

