I have a requirement to use same variable of a request scoped backing bean which is a List datatype for h:selectOneListbox and h:selectManyListbox. I get "ip: Validation Error: Value is not valid" error with h:selectOneListbox even after using a converter. Can some one help me resolving this ?
In page1.xhtml I've given it as:
<h:selectManyListbox id="ip" value="#{inputBean.ipAddress}" size="5">
<f:selectItems value="#{inputBean.ipAddressList}" />
</h:selectManyListbox>
In page2.xhtml I've given it as:
<h:selectOneListbox id="ip" value="#{inputBean.ipAddress}" size="5">
<f:selectItems value="#{inputBean.ipAddressList}" />
<f:converter converterId="ipAddressConverter"></f:converter>
</h:selectOneListbox>
My Input bean, a request scoped managed bean looks like this:
@ManagedBean
@RequestScoped
public class InputTablePlot implements Serializable{
private static final long serialVersionUID = 1L;
@ManagedProperty("#{database}")
private Database database;
private Connection connection;
private StringBuilder query;
private PreparedStatement pst_query;
private ResultSet rs;
private List<Long> ipAddress;
private Map<String, Long> ipAddrMenu;
public InputBean()
{
ipAddrMenu = new LinkedHashMap<String, Long>();
}
@PostConstruct
public void init()
{
ipAddrMenu.clear();
try
{
connection = database.getDbConnection();
query = new StringBuilder();
query.append("SELECT distinct source AS ipaddr FROM addrtable ORDER BY source");
pst_query = connection.prepareStatement(query.toString());
rs = pst_query.executeQuery();
while (rs.next())
{
ipAddrMenu.put(ipLongToString(rs.getLong("ipaddr")), rs.getLong("ipaddr")); // Adding
// sources
}
rs.close();
pst_query.close();
connection.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
public List<Long> getIpAddress()
{
System.out.println("In Getter" + ipAddress);
return ipAddress;
}
public void setIpAddress(List<Long> ipAddress)
{
System.out.println("In Setter");
System.out.println(ipAddress);
this.ipAddress = ipAddress;
}
public Map<String, Long> getIpAddressList()
{
return ipAddrMenu;
}
public void setIpAddressList(Map<String, Long> ipAddressList)
{
this.ipAddrMenu = ipAddressList;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((connection == null) ? 0 : connection.hashCode());
result = prime * result + ((database == null) ? 0 : database.hashCode());
result = prime * result + ((ipAddrMenu == null) ? 0 : ipAddrMenu.hashCode());
result = prime * result + ((ipAddress == null) ? 0 : ipAddress.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
InputBean other = (InputBean) obj;
if (connection == null)
{
if (other.connection != null)
return false;
}
else if (!connection.equals(other.connection))
return false;
if (database == null)
{
if (other.database != null)
return false;
}
else if (!m_database.equals(other.database))
return false;
if (ipAddrMenu == null)
{
if (other.ipAddrMenu != null)
return false;
}
else if (!ipAddrMenu.equals(other.ipAddrMenu))
return false;
if (ipAddress == null)
{
if (other.ipAddress != null)
return false;
}
else if (!ipAddress.equals(other.ipAddress))
return false;
return true;
}
}
Converter code:
import java.util.ArrayList;
import java.util.List;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
public class IpAddressConverter implements Converter
{
@Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2)
{
List<Long> ipAddr = new ArrayList<Long>();
try{
ipAddr.add(Long.valueOf(arg2));
}catch(NumberFormatException e){
e.printStackTrace();
FacesContext facesContext = FacesContext.getCurrentInstance();
FacesMessage facesMessage = new FacesMessage("Problem with conversion of ip!");
facesContext.addMessage(null, facesMessage);
}
for(int i=0; i< ipAddr.size(); i++){
System.out.println("ipAddr >>> "+ipAddr);
}
return ipAddr;
}
@Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2)
{
String val = null;
try{
Long ip = (Long) arg2;
val = ip.toString();
}catch(Exception e){
e.printStackTrace();
FacesContext facesContext = FacesContext.getCurrentInstance();
FacesMessage facesMessage = new FacesMessage("Problem with conversion of ip!");
facesContext.addMessage(null, facesMessage);
}
System.out.println("value >>> "+val);
return val;
}
}
It failed because List<Long>
as returned by the converter doesn't match the individual Long
item of the available items while JSF is validating the submitted (and converted!) value against the list of available items (as part of safeguard against tampered/spoofed HTTP requests wherein attacker manipulated the selected item value). The converter is supposed to return a Long
. All with all, such a converter is simply insuitable for usage in an UISelectOne
component.
You'd better bind the value straight to a single property. If you insist in using a List
property, then just prepare it with a single empty item and specify the list item index in the value.
private List<Long> ipAddress = new ArrayList<>(1);
with
<h:selectOneListbox id="ip" value="#{inputBean.ipAddress[0]}" size="5">
<f:selectItems value="#{inputBean.ipAddressList}" />
</h:selectOneListbox>