JSF - java.lang.NumberFormatException: For input string: "" - Converter class - jsf

I'm trying to write some simple login page in JSF and I don't really understand the converter class. I have this error when I try to login:
JSF - java.lang.NumberFormatException: For input string: ""
My controller class:
#ManagedBean(name="main")
#SessionScoped
#PersistenceContext(name = "persistence/LogicalName", unitName = "ProjectPU")
public class MainController {
private EntityManager em;
#Resource
private javax.transaction.UserTransaction utx;
#PersistenceUnit(unitName="ProjectPU")
private EntityManagerFactory emf;
/**
* Creates a new instance of MainController
*/
Users user = new Users();
public Users getUser() {
return user;
}
public void setUser(Users user) {
this.user = user;
}
private EntityManager getEntityManager()
{
return emf.createEntityManager();
}
public MainController() {
}
public String signin()
{
EntityManager em = getEntityManager();
TypedQuery<Users> query = em.createNamedQuery("Users.findByLogin", Users.class);
query.setParameter("login", user.getLogin());
Users result = null;
try{
result = query.getSingleResult();
} catch(javax.persistence.NoResultException a){
}
if (result != null) {
if(result.getPassword().equals(user.getPassword())){
Util.getSession().setAttribute("login", user.getLogin());
return "index.xhtml";
}
} else {
return "signin.xhtml";
}
return "index.xhtml";
}
public Object findUser(Integer id) {
EntityManager em = getEntityManager();
try {
Users u = (Users) em.find(Users.class, id);
return u;
} finally {
em.close();
}
}
}
My converter class:
#FacesConverter("Converters.UsersConverter")
public class UsersConverter implements Converter
{
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value)
{
if (!value.equals("null"))
{
Integer id = new Integer(value);
MainController controller = (MainController) context.getApplication().getELResolver().getValue(
context.getELContext(), null, "main");
return controller.findUser(id);
}
else
{
return null;
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value)
{
if (value == null) {
return null;
}
if(value instanceof Users)
{
Users u = (Users) value;
return "" + u.getId();
}
else
{
throw new IllegalArgumentException("object:" + value + " of type:" + value.getClass().getName() + "; expected type: Users");
}
}
}
and my view(Index page):
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org /TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<h:form>
<table>
<h:inputHidden value="#{main.user}" immediate="true"/>
<tr><td>Login:</td><td><h:inputText id="login" value="# {main.user.login}"/></td></tr>
<tr><td>Password:</td><td><h:inputSecret id="password" value="#{main.user.password}"/></td></tr>
</table>
<h:commandButton id="submit" value="Signin" action="#{main.signin()}"/>
</h:form>
</h:body>
</html>
I created database I have there a table User and I added one user and I cant login. On debugger I can see null values in my converter in both methods(getasobject and getasstring).

Related

How to bean-validate a collection property in a jsf composite component, constraints do not fire

How do I define a jsf composite component properly such that its value gets bean-validated correctly in the case it contains a collection?
We have an entity that references a collection of details. Both are annotated with bean-validation-constraints. Please note the annotations at the details-property.
public class Entity implements Serializable {
#NotEmpty
private String name;
#NotEmpty
#UniqueCategory(message="category must be unique")
private List<#Valid Detail> details;
/* getters/setters */
}
public class Detail implements Serializable {
#Pattern(regexp="^[A-Z]+$")
private String text;
#NotNull
private Category category;
/* getters/setters */
}
public class Category implements Serializable {
private final int id;
private final String description;
Category(int id, String description) {
this.id = id;
this.description = description;
}
/* getters/setters */
}
public class MyConstraints {
#Target({ ElementType.TYPE, ElementType.FIELD })
#Retention(RetentionPolicy.RUNTIME)
#Constraint(validatedBy = UniqueCategoryValidator.class)
#Documented
public static #interface UniqueCategory {
String message();
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public static class UniqueCategoryValidator implements ConstraintValidator<UniqueCategory, Collection<Detail>> {
#Override
public boolean isValid(Collection<Detail> collection, ConstraintValidatorContext context) {
if ( collection==null || collection.isEmpty() ) {
return true;
}
Set<Category> set = new HashSet<>();
collection.forEach( d-> set.add( d.getCategory() ));
return set.size() == collection.size();
}
public void initialize(UniqueCategory constraintAnnotation) {
// intentionally empty
}
}
private MyConstraints() {
// only static stuff
}
}
The entity can be edited in a jsf-form, where all the tasks concerning the details are encapsulated in a composite component, eg
<h:form id="entityForm">
<h:panelGrid columns="3">
<p:outputLabel for="#next" value="name"/>
<p:inputText id="name" value="#{entityUiController.entity.name}"/>
<p:message for="name"/>
<p:outputLabel for="#next" value="details"/>
<my:detailsComponent id="details" details="#{entityUiController.entity.details}"
addAction="#{entityUiController.addAction}"/>
<p:message for="details"/>
<f:facet name="footer">
<p:commandButton id="saveBtn" value="save"
action="#{entityUiController.saveAction}"
update="#form"/>
</f:facet>
</h:panelGrid>
</h:form>
where my:detailsComponent is defined as
<ui:component xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:p="http://primefaces.org/ui"
>
<cc:interface>
<cc:attribute name="details" required="true" type="java.lang.Iterable"/>
<cc:attribute name="addAction" required="true" method-signature="void action()"/>
</cc:interface>
<cc:implementation>
<p:outputPanel id="detailsPanel">
<ui:repeat id="detailsContainer" var="detail" value="#{cc.attrs.details}">
<p:inputText id="text" value="#{detail.text}" />
<p:message for="text"/>
<p:selectOneMenu id="category" value="#{detail.category}"
converter="#{entityUiController.categoriesConverter}"
placeholder="please select" >
<f:selectItem noSelectionOption="true" />
<f:selectItems value="#{entityUiController.categoryItems}"/>
</p:selectOneMenu>
<p:message for="category"/>
</ui:repeat>
</p:outputPanel>
<p:commandButton id="addDetailBtn" value="add" action="#{cc.attrs.addAction}"
update="detailsPanel" partialSubmit="true" process="#this detailsPanel"/>
</cc:implementation>
</ui:component>
and the EntityUiController is
#Named
#ViewScoped
public class EntityUiController implements Serializable {
private static final Logger LOG = Logger.getLogger( EntityUiController.class.getName() );
#Inject
private CategoriesBoundary categoriesBoundary;
#Valid
private Entity entity;
#PostConstruct
public void init() {
this.entity = new Entity();
}
public Entity getEntity() {
return entity;
}
public void saveAction() {
LOG.log(Level.INFO, "saved entity: {0}", this.entity );
}
public void addAction() {
this.entity.getDetails().add( new Detail() );
}
public List<SelectItem> getCategoryItems() {
return categoriesBoundary.getCategories().stream()
.map( cat -> new SelectItem( cat, cat.getDescription() ) )
.collect( Collectors.toList() );
}
public Converter<Category> getCategoriesConverter() {
return new Converter<Category>() {
#Override
public String getAsString(FacesContext context, UIComponent component, Category value) {
return value==null ? null : Integer.toString( value.getId() );
}
#Override
public Category getAsObject(FacesContext context, UIComponent component, String value) {
if ( value==null || value.isEmpty() ) {
return null;
}
try {
return categoriesBoundary.findById( Integer.valueOf(value).intValue() );
} catch (NumberFormatException e) {
throw new ConverterException(e);
}
}
};
}
}
When we now press the save-button in the above h:form, the name-inputText is validated correctly but the #NotEmpty- and #UniqueCategory-constraint on the details-property are ignored.
What am I missing?
We are on java-ee-7, payara 4.
After diving into this a bit we endet up with a solution using a backing component ValidateListComponent. It was inspired by UIValidateWholeBean and WholeBeanValidator.
That component extends from UIInput and overrides the validation-Methods to operate on a clone of the above details-collection which gets populated with the already validated values of the children-UIInput. Seems to work for now.
<ui:component ...>
<cc:interface componentType="validatedListComponent">
<cc:attribute name="addAction" required="true" method-signature="void action()"/>
</cc:interface>
<cc:implementation>
... see above ...
</cc:implementation>
</ui:component>
with the backing component defined as
#FacesComponent(value = "validatedListComponent")
#SuppressWarnings("unchecked")
public class ValidatedListComponent extends UIInput implements NamingContainer {
#Override
public String getFamily() {
return "javax.faces.NamingContainer";
}
/**
* Override {#link UIInput#processValidators(FacesContext)} to switch the order of
* validation. First validate this components children, then validate this itself.
*/
#Override
public void processValidators(FacesContext context) {
// Skip processing if our rendered flag is false
if (!isRendered()) {
return;
}
pushComponentToEL(context, this);
for (Iterator<UIComponent> i = getFacetsAndChildren(); i.hasNext(); ) {
i.next().processValidators(context);
}
if (!isImmediate()) {
Application application = context.getApplication();
application.publishEvent(context, PreValidateEvent.class, this);
executeValidate(context);
application.publishEvent(context, PostValidateEvent.class, this);
}
popComponentFromEL(context);
}
/**
* Override {#link UIInput#validate(FacesContext)} to validate a cloned collection
* instead of the submitted value.
*
* Inspired by {#link UIValidateWholeBean} and {#link WholeBeanValidator}.
*/
#Override
public void validate(FacesContext context) {
AreDetailsValidCallback callback = new AreDetailsValidCallback();
visitTree( VisitContext.createVisitContext(context)
, callback
);
if ( callback.isDetailsValid() ) {
Collection<?> clonedValue = cloneCollectionAndSetDetailValues( context );
validateValue(context, clonedValue);
}
}
/**
* private method copied from {#link UIInput#executeValidate(FacesContext)}.
* #param context
*/
private void executeValidate(FacesContext context) {
try {
validate(context);
} catch (RuntimeException e) {
context.renderResponse();
throw e;
}
if (!isValid()) {
context.validationFailed();
context.renderResponse();
}
}
private Collection<Object> cloneCollectionAndSetDetailValues(FacesContext context) {
ValueExpression collectionVE = getValueExpression("value");
Collection<?> baseCollection = (Collection<?>) collectionVE.getValue(context.getELContext());
if ( baseCollection==null ) {
return null;
}
// Visit all the components children to find their already validated values.
FindDetailValuesCallback callback = new FindDetailValuesCallback(context);
this.visitTree( VisitContext.createVisitContext(context)
, callback
);
// Clone this components value and put in all cloned details with validated values set.
try {
Collection<Object> clonedCollection = baseCollection.getClass().newInstance();
for( Entry<Object,Map<String,Object>> entry : callback.getDetailSubmittedData().entrySet() ) {
Object clonedDetail = cloneDetailAndSetValues( entry.getKey(), entry.getValue() );
clonedCollection.add( clonedDetail );
}
return clonedCollection;
} catch ( Exception e ) {
throw new ConverterException(e);
}
}
private <T> T cloneDetailAndSetValues(T detail, Map<String, Object> propertyMap) throws Exception {
T clonedDetail = clone(detail);
// check the properties we have in the detail
Map<String, PropertyDescriptor> availableProperties = new HashMap<>();
for (PropertyDescriptor propertyDescriptor : getBeanInfo(detail.getClass()).getPropertyDescriptors()) {
availableProperties.put(propertyDescriptor.getName(), propertyDescriptor);
}
// put their value (or local value) into our clone
for (Map.Entry<String, Object> propertyToSet : propertyMap.entrySet()) {
availableProperties.get(propertyToSet.getKey()).getWriteMethod().invoke(clonedDetail,
propertyToSet.getValue());
}
return clonedDetail;
}
private static <T> T clone(T object) throws Exception {
// clone an object using serialization.
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteArrayOutputStream);
out.writeObject(object);
byte[] bytes = byteArrayOutputStream.toByteArray();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
ObjectInputStream in = new ObjectInputStream(byteArrayInputStream);
return (T) in.readObject();
}
private class FindDetailValuesCallback implements VisitCallback {
private final FacesContext context;
private final Map<Object, Map<String, Object>> detailSubmittedData = new HashMap<>();
public FindDetailValuesCallback(final FacesContext context) {
this.context = context;
}
final Map<Object, Map<String, Object>> getDetailSubmittedData() {
return detailSubmittedData;
}
#Override
public VisitResult visit(VisitContext visitContext, UIComponent component) {
if ( isVisitorTarget(component) ) {
ValueExpression ve = component.getValueExpression("value");
Object value = ((EditableValueHolder)component).getValue();
if (ve != null) {
ValueReference vr = ve.getValueReference(context.getELContext());
String prop = (String)vr.getProperty();
Object base = vr.getBase();
Map<String, Object> propertyMap
= Optional.ofNullable( detailSubmittedData.get(base) )
.orElseGet( HashMap::new );
propertyMap.put(prop, value );
detailSubmittedData.putIfAbsent( base, propertyMap);
}
}
return ACCEPT;
}
}
private class AreDetailsValidCallback implements VisitCallback {
private boolean detailsValid;
public AreDetailsValidCallback() {
this.detailsValid = true;
}
public boolean isDetailsValid() {
return detailsValid;
}
#Override
public VisitResult visit(VisitContext visitContext, UIComponent component) {
if ( isVisitorTarget(component) ) {
if ( !((EditableValueHolder)component).isValid() ) {
this.detailsValid = false;
}
}
return ACCEPT;
}
}
private boolean isVisitorTarget( UIComponent component ) {
return component instanceof EditableValueHolder && component.isRendered()
&& component!=ValidatedListComponent.this;
}
}
UPDATE: sometimes it is a problem to obtain the ValueReference in FindDetailValuesCallback#visit. The answer given by Michele here solved that problem.

How to get UISelectMany custom component value in a managed bean

I have a project which consist in a treeview of a folder.
I decided to create a custom component.
The XHTML looks great, I can get the request param of the selected files on the decode method.
The problem is: I can't obtain the value on a managedBean attribute (see submit method)...
here is my code, I don't understand what is wrong or I miss...
Custom Component
#FacesComponent(createTag = true, tagName = "indexComponent", namespace = "http://index.com/tags")
public class IndexComponent extends UISelectMany{
private String pathString = "/home/test/";
private List<Path> filesNames = new ArrayList<>();
private static String NAME_CHKBOX = "checkbox";
IndexComponent instance = this;
public IndexComponent getInstance() {
return instance;
}
public void setInstance(IndexComponent instance) {
this.instance = instance;
}
#Override
public String getFamily() {
return "treeview";
}
#Override
public void encodeBegin(FacesContext context) throws IOException{
ResponseWriter writer = context.getResponseWriter();
writer.startElement("ul", this);
writer.writeAttribute("data-role", "treeview", null);
writer.writeAttribute("id", this.getClientId(context), null);
Files.walkFileTree(Paths.get(pathString), new HashSet<>(),2, new FileVisitor<Path>() {
#Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
filesNames.add(dir);
writer.startElement("li", instance);
writer.writeAttribute("data-caption", dir.getFileName() , null);
writer.writeAttribute("class", "" , null);
writer.startElement("ul", instance);
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
filesNames.add(file);
writer.startElement("li", instance);
writer.startElement("input", instance);
writer.writeAttribute("type", "checkbox" , null);
writer.writeAttribute("name", getHtmlNameCheckBox(context) , null);
writer.writeAttribute("value", file.getFileName() , null);
writer.writeAttribute("data-role", "checkbox" , null);
writer.writeAttribute("data-caption", file.getFileName() , null);
writer.writeAttribute("title", "" , null);
writer.endElement("input");
writer.endElement("li");
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
writer.endElement("li");
writer.endElement("ul");
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
writer.startElement("li", instance);
writer.writeAttribute("data-caption", file.getFileName() , null);
writer.endElement("li");
return FileVisitResult.CONTINUE;
}
});
writer.endElement("ul");
instance.encodeEnd(context);
}
public List<Path> getFilesNames() {
return filesNames;
}
public void setFilesNames(List<Path> filesNames) {
this.filesNames = filesNames;
}
#Override
public void decode(FacesContext context) {
String[] result = context.getExternalContext().getRequestParameterValuesMap().get( getHtmlNameCheckBox(context) );
if(result != null && result.length > 0) {
List<String> liste = Arrays.asList( result );
this.setSubmittedValue(liste);
}
}
private String getHtmlNameCheckBox(FacesContext context){
return String.format("%s:%s", this.getClientId(context), NAME_CHKBOX);
}
}
ManadgeBean
#Named
#ViewScoped
public class IndexBean implements Serializable{
private static final long serialVersionUID = -1L;
private List<String> filesNames;
#PostConstruct
public void init() {
filesNames = new ArrayList<>();
}
public void submit() {
LogUtils.info("submit !!!");
for (String s : filesNames) {
LogUtils.info(s);
}
}
public List<String> getFilesNames() {
return filesNames;
}
public void setFilesNames(List<String> filesNames) {
this.filesNames = filesNames;
}
}
XHTML
<!DOCTYPE html>
<h:html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:t="http://index.com/tags"
xmlns:composite="http://java.sun.com/jsf/composite">
<h:head>
<h:outputStylesheet name="metro-all.css" library="css" />
<h:outputScript name="jquery-3.3.1.min.js" library="js" />
<h:outputScript name="metro.js" library="js" />
</h:head>
<h:body>
<h:form>
<t:indexComponent value="#{indexBean.filesNames}" />
<h:commandButton actionListener="#{indexBean.submit()}" type="submit" styleClass="button primary" value="Submit" />
</h:form>
</h:body>
</h:html>
Note : I don't want to use Primefaces or other framework.

primefaces p:schedule didn't show up at first time

I am using a p:schedule but it won't show up at the first time I entered the page
I have to refresh the page once and then it comes out.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:form id="form">
<h:outputScript library="js" name="primefaces-locale-zh.js" />
<div class="top-extra-title">
<h:outputText value="#{menu.miMeetingScheduleView}" />
</div>
<p:schedule id="schedule" value="#{meetingScheduleView.meetingSchedule}"
widgetVar="meetingSchedule" timeZone="GMT+8" draggable="false"
locale="zh" >
<p:ajax partialSubmit="true" event="eventSelect" listener="#{meetingScheduleView.onEventSelect}"
update="mform :content" />
</p:schedule>
</h:form>
</ui:composition>
#ManagedBean(name = "meetingScheduleView")
#ViewScoped
public class MeetingScheduleView implements Serializable {
private static final long serialVersionUID = 1L;
SessionUser sessionUser;
private String accountOrgId;
private static final String msgFile = "cyberstar.module.meeting.meeting";
private List<Meeting> meetingList;
private ScheduleModel meetingSchedule;
private ScheduleEvent event;
#ManagedProperty(value = "#{sysAdminPage}")
private SysAdminPage sysAdminPage;
#PostConstruct
public void init() {
sessionUser = JSFUtil.getSessionUser();
if(sessionUser==null){
MsgUtil.showErrorMsg(msgFile, "infSessionUserFail", "infSessionUserFailDetail");
sessionUser.logoff();
}
accountOrgId = sessionUser.getOperator().getOrgId();
meetingList = new ArrayList<Meeting>();
meetingSchedule = new DefaultScheduleModel();
event = new DefaultScheduleEvent();
initialize();
}
public void sendMeetingUnid(){
ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
String issueUnid = context.getRequestParameterMap().get("meetingUnid");
LinkedHashMap<String , String> hm = new LinkedHashMap<String , String>();
if (sessionUser.getSendDataMap().get("meetingView") == null) {
hm.put("meetingUnid", issueUnid);
sessionUser.getSendDataMap().put("meetingView", hm);
} else {
hm = sessionUser.getSendDataMap().get("meetingView");
hm.put("meetingUnid", issueUnid);
}
}
public void initialize(){
try {
if (sessionUser.isCyberStar()) {
meetingList = MeetingDAO.getAllMeeting();
} else {
meetingList = MeetingDAO.getMeetingByOrgId(accountOrgId);
}
for (int i = 0; i < meetingList.size(); i++) {
Meeting m = meetingList.get(i);
if (m.getStatus().equals(MeetingStatus.sketch)) {
continue;
}
DefaultScheduleEvent dsEvent = new DefaultScheduleEvent(m.getTitle(), m.getStartTime(), m.getEndTime(),m.getUnid());
if(m.getStatus().equals(MeetingStatus.cancel)){
dsEvent.setStyleClass("redEvent");
}
meetingSchedule.addEvent(dsEvent);
}
} catch (SQLException e) {
MsgUtil.showErrorMsg(msgFile, "infUpdateFail",
"infUpdateFailSQLExceptionDetail");
e.printStackTrace();
}
}
public void onEventSelect(SelectEvent selectEvent) {
event = (ScheduleEvent) selectEvent.getObject();
String issueUnid = String.valueOf(event.getData());
LinkedHashMap<String , String> hm = new LinkedHashMap<String , String>();
if (sessionUser.getSendDataMap().get("meetingView") == null) {
hm.put("meetingUnid", issueUnid);
sessionUser.getSendDataMap().put("meetingView", hm);
} else {
hm = sessionUser.getSendDataMap().get("meetingView");
hm.put("meetingUnid", issueUnid);
}
try {
sysAdminPage.openView("meetingForm");
} catch (IOException e) {
MsgUtil.showErrorMsg(msgFile, "infUpdateFail", "infUpdateFailExceptionDetail");
e.printStackTrace();
}
}
these are the codes of button which direct to the page
<p:menuitem value="#{menu.miMeetingScheduleView}" styleClass="meetingScheduleView"
onclick="highlightme('meetingScheduleView')" action="#{sysAdminPage.menuSelected}"
update="mform :content">
<f:param name="viewname" value="meetingScheduleView" />
</p:menuitem>
my goal is to show the p:schedule just when I enter the page

Pass Object value in Primefaces SelectOneMenu

Hello i am Using PrimeFaces 4.0 and i need to pass object value in SelectOneMenu.
I am using converter to convert that from string format to Class object format.
These are the code files please help me...
lablevalue.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
</h:head>
<h:body>
<h:form id="myform">
<p:growl showDetail="true"></p:growl>
<p:selectOneMenu value="#{itemlableAcction.idCard}" >
<f:converter converterId="converter.SelectMenUConverter" />
<f:selectItem itemLabel="Select" itemValue="" />
<f:selectItems value="#{itemlableAcction.idCards}" var="idv" itemLabel="#{idv.name}" itemValue="#{idv}" />
</p:selectOneMenu>
<h:commandButton action="#{itemlableAcction.onclickSubmit}" value="Submit"></h:commandButton>
</h:form>
</h:body>
</html>
ItemlableAcction
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import bo.IdCard;
#ManagedBean
public class ItemlableAcction {
List<IdCard> idCards = new ArrayList<IdCard>();
IdCard idCard;
public Object getIdCard() {
return idCard;
}
public void setIdCard(IdCard idCard) {
this.idCard = idCard;
}
public List<IdCard> getIdCards() {
return idCards;
}
public void setIdCards(List<IdCard> idCards) {
this.idCards = idCards;
}
public ItemlableAcction() {
IdCard card1 = new IdCard();
card1.setId(1);
card1.setName("ABC");
card1.setAddress("USA");
idCards.add(card1);
IdCard card2 = new IdCard();
card2.setId(2);
card2.setName("MNO");
card2.setAddress("INDIA");
idCards.add(card2);
IdCard card3 = new IdCard();
card3.setId(3);
card3.setName("XYZ");
card3.setAddress("Chaina");
idCards.add(card3);
}
public String onclickSubmit() {
IdCard ic = (IdCard) idCard;
System.out.println("In action id values are " + ic.getId() + " " + ic.getAddress());
return "";
}
}
SelectMenUConverter
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import bo.IdCard;
#FacesConverter("converter.SelectMenUConverter")
public class SelectMenUConverter implements Converter {
public SelectMenUConverter() {
System.out.println("Inside converter");
}
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) {
System.out.println("One" + arg2);
IdCard idCard = new IdCard(arg2);
return idCard;
}
public String getAsString(FacesContext arg0, UIComponent arg1, Object value) {
System.out.println("Two" + value);
return value.toString();
}
}
Idcard
public class IdCard {
String name;
int id;
String address;
public IdCard() {
}
public IdCard(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Imagine you have to implement converter for 100 classes.
If you don't want to implement a own Converter and get the data from exiting list, use:
SelectItems Converter Omnifaces
You have a complete example.
PD: Don't forget to implement toString with a unique id.(See documentation)
You're not searching and getting the required instance from the defined list (in your managed-bean) when getting its identifiant through getAsObject()'s method. You're just instanciating an additional new object through the converter. Try this:
#FacesConverter("converter.SelectMenUConverter")
public class SelectMenUConverter implements Converter {
...
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) {
if (arg2 == null || arg2.isEmpty()) {return null;}
try {
return findIdCard(arg2); // here's where should be retreived the desired selected instance
} catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage(("This is not a valid card id")), e);
}
}
...
public IdCard findIdCard(String id) {
Iterator<IdCard> iterator = idCards.iterator(); // "idCards" represents your idCards' list. It is not recognized yet in the converter
while(iterator.hasNext()) {
IdCard idc = iterator.next();
if(idc.getId() == Integer.valueOf(id).intValue()) {
return idc;
}
}
return null;
}

how can i call setter without calling <f:viewparam> converter?

i am using jsf 2.1.1 and primefaces 3.0.M4. i have a sample jsf page that used to post country comments. i use f:viewparam tag with converter to view country pages. here are the codes:
country.xhtml:
<f:metadata>
<f:viewParam name="country" value="#{countryBean2.selectedCountry}" converter="countryConverter" required="true"/>
</f:metadata>
<h:head>
<title>Country</title>
</h:head>
<h:body>
<h:form id="form">
<h:outputText value="#{countryBean2.selectedCountry.countryName}" />
<br/><br/>
<h:outputText value="Comment:" />
<h:inputText value="#{countryBean2.comment}" />
<br/>
<p:commandButton value="Send" action="#{countryBean2.sendComment}" update="#this" />
</h:form>
</h:body>
CountryBean2.java:
#Named("countryBean2")
#SessionScoped
public class CountryBean2 implements Serializable {
private EntityCountry selectedCountry;
private String comment;
public EntityCountry getSelectedCountry() { return selectedCountry; }
public void setSelectedCountry(EntityCountry newValue) { selectedCountry = newValue; }
public String getComment() { return comment; }
public void setComment(String newValue) { comment = newValue; }
EntityManagerFactory emf = Persistence.createEntityManagerFactory("testPU");
public void sendComment() {
EntityManager em = emf.createEntityManager();
try {
FacesMessage msg = null;
EntityTransaction entr = em.getTransaction();
boolean committed = false;
entr.begin();
try {
EntityCountryComment c = new EntityCountryComment();
c.setCountry(selectedCountry);
c.setComment(comment);
em.persist(c);
committed = true;
msg = new FacesMessage();
msg.setSeverity(FacesMessage.SEVERITY_INFO);
msg.setSummary("Comment was sended");
} finally {
if (!committed) entr.rollback();
}
} finally {
em.close();
}
}
}
CountryConverter.java:
public class CountryConverter implements Converter {
public static EntityCountry country = new EntityCountry();
EntityManagerFactory emf = Persistence.createEntityManagerFactory("testPU");
#Override
public EntityCountry getAsObject(FacesContext context, UIComponent component, String value) {
EntityManager em = emf.createEntityManager();
Query query = em.createQuery("SELECT c FROM EntityCountry c WHERE c.countryName = :countryName")
.setParameter("countryName", value);
country = (EntityCountry) query.getSingleResult();
return country;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
EntityCountry c = (EntityCountry) value;
return c.getCountryName();
}
}
i want to call "setComment" setter without calling CountryConverter, when i am using commandbutton to post comment. how can i do that ?
Unfortunately, that's by design of the <f:viewParam> component. It will convert the request parameter and set the property on every HTTP request, also on postbacks. In order to change this behaviour, you would need to extend <f:viewParam> with a custom component which doesn't remember the initial request parameter in its state. It's relatiely simple, instead of delegating the setSubmittedValue() and getSubmittedValue() to StateHelper, you just need to make it an instance variable. This is described in detail in this blog.
#FacesComponent("com.my.UIStatelessViewParameter")
public class UIStatelessViewParameter extends UIViewParameter {
private String submittedValue;
#Override
public void setSubmittedValue(Object submittedValue) {
this.submittedValue = (String) submittedValue;
}
#Override
public String getSubmittedValue() {
return submittedValue;
}
}
OmniFaces has an ready-to-use component for this in flavor of <o:viewParam>. Here is the live example.

Resources