Setter of h:selectOneMenu is not invoked [duplicate] - jsf-2

This question already has answers here:
Conversion Error setting value for 'null Converter' - Why do I need a Converter in JSF?
(2 answers)
Closed 6 years ago.
I just tried to change a value of a select input box. Loading the page runs into my breakpoint for the getter method of the pubcategory property. Good so far. Changing the value, does NOT invoke the setter method. I trigger an Richfaces ajax processing. I confirm, that all JSF phases are walked through (I also see the JPA-SQL select queries, where I would expect an update statement for changing the value - well, can't be, if the setter method is not triggered). This is my selectOneMenu code
<h:selectOneMenu id="pubCategoryId" converter="#{pubCategoryConverter}" value="#{pubController.pubCategory}">
<f:selectItems value="#{listPubCategoryController.pubCategories}" var="category" itemLabel="#{category.name}" itemValue="#{category}" />
<a4j:ajax event="change" execute="#this" />
</h:selectOneMenu>
<h:message for="pubCategoryId" style="color:red" />
My converter is invoked on both times. the getAsString method, when I load the page and the getAsObject when the on-change action is triggered. From this I concluse, the change really goes back to the server. But - again - it never triggers the setter method.
#ManagedBean(name = "pubCategoryConverterController")
#FacesConverter(value = "pubCategoryConverter")
//#Named
public class PubCategoryConverter implements Converter {
#Inject
private PubCategoryRepository pubCategoryRepository;
public PubCategoryConverter() {
}
// from page to backing bean
#Override
public Object getAsObject(FacesContext ctx, UIComponent component,
String value) {
PubCategory pubCat = pubCategoryRepository.getPubCategoryById(new Long(
value));
return pubCat;
}
// from backing bean to page
#Override
public String getAsString(FacesContext fc, UIComponent uic, Object o) {
PubCategory pubCat = ((PubCategory) o);
return pubCat.getId().toString();
}
}
Same story if I annotate the converter with #Named instead of #FacesConverter/#ManagedBean. Any clue or hints anyone?
Using JBoss 7.1.1, Richfaces 4.3.3, JSF 2.0

The converter is called in the "Process Validations" phase of the JSF lifecycle whereas the setter is called later, during the "Update Model Values" phase. Each phase goes through the entire page which means a validation error in any component will prevent all model updates. If you're not seeing validation errors on the page try checking your message tags.
The skipping of lifecycle phases is done by calling FacesContext.renderResponse(). See UIInput.executeValidate() and LifeCycleImpl.execute() for details.

I hooked up the phase listener and printed the event.getFacesContext().getMessageList(). And, there is an error although not printed to the <h:Message for="pubCategoryId"/>. The error is msg j_idt18:pubFormE:pubCategoryId: Validation Error: Value is not valid
package com.foo;
import java.util.List;
import java.util.logging.Logger;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseListener;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
public class PhaseTracker implements PhaseListener {
private static final Logger logger = Logger.getLogger("org.exadel.helper");
public void beforePhase(PhaseEvent e) {
List<FacesMessage> msgs = e.getFacesContext().getMessageList();
for (FacesMessage msg : msgs) {
logger.info("before msg " + msg.getSummary() + " :: " + msg.getDetail());
}
logger.info("BEFORE " + e.getPhaseId());
}
public void afterPhase(PhaseEvent e) {
logger.info("AFTER " + e.getPhaseId());
}
}
The issue is with the equals(Object o) method within of the model object (some call that DTO). As stated in many forums, the values that you compare within this method must not look like e.g. this.id == o.id, because it compares instances not the inner state. Use equals instead this.id.equals(o.id). Once that is fixed the error Value is not valid will go away.
After all, I noticed the following. If you want to use the selectOneMenu with the tag attribute converter instead of <f:converter ../>, e.g. ...
<h:selectOneMenu value="#{pubController.pubCategory}" converter="#{pubCategoryConverterController}">
... you need to annotate your converter also as a #ManagedBean instance in addition to #FacesConverter, e.g.
#ManagedBean(name="pubCategoryConverterController")
#FacesConverter(value = "pubCategoryConverter")
On the other hand, if you want to use <f:converter converterId="pubCategoryConverter"> tag, you need to reference the faces converter name - NOT an instance of a managed bean. Notice, there is no EL #{...} around the converter name. However, in this case, you CANNOT inject a bean into your converter. As a consequence, in your converter bean, you need to instantiate a controller from the application context in order to use EJB services. e.g.
PubCategoryController pubCategoryController = ctx.getApplication().evaluateExpressionGet(ctx, "#{pubCategoryController}", PubCategoryController.class);

Related

How to get field's class type of back bean with converter in jsf? [duplicate]

Let's suppose I have following structure:
1) Managed Bean:
#ViewScoped
#ManagedBean
public class TestBean {
private Test test;
//getters/setters
}
2) Test class:
public class Test {
private String attribute;
//gets/sets
}
3) XHTML
<p:inputText id="test" value="#{testBean.test.atribute}" />
Now, I know there is a way to find and get component instance:
UIComponent c = view.findComponent(s);
From UIComponent, how do I get the type bound to component?
What I need is to get full qualified class name from what is set as "value" attribute in component. Something like: package.Test.attribute.
UIComponent offers getValueExpression("attributeName")
sample :
UIViewRoot viewRoot = Faces.getViewRoot();
UIComponent component= viewRoot.findComponent("x");
ValueExpression value = component.getValueExpression("value");
Class<?> expectedType = value.getType(Faces.getELContext());
NB:Faces here is from Omnifaces, which is a "Collection of utility methods for the JSF API that are mainly shortcuts for obtaining stuff from the thread local FacesContext. "
excepts from getType() javadoc
public abstract Class getType(ELContext context) Evaluates the
expression relative to the provided context, and returns the most
general type that is acceptable for an object to be passed as the
value parameter in a future call to the setValue(javax.el.ELContext. java.lang.Object) method. This is not always the same as
getValue().getClass(). For example, in the case of an expression that
references an array element, the getType method will return the
element type of the array, which might be a superclass of the type of
the actual element that is currently in the specified array element.
For MethodExpression read this.

java struts2 very strange behaviour while using iterator

public class UserAction{
private UserData user;
//getter, setter
public String Load() {
user = UserDao.getInstance().getItem(getUserContext().getId());
request.getSession().setAttribute("item", user);
return super.Load();
}
}
public class PropertyAction {
private List <PropertyData> propertyList;
//getter, setter
#Override
public String execute() throws Exception {
propertyList=PropertyDao.getInstance().getItems();
return "list";
}
}
jsp:
<s:iterator value="propertyList" var="item">
${item.name}
${item.thema}
${item.desc}
</s:iterator>
I want to show very strange behaviour of Struts2.
I click property link -> then run PropertyAction.execute() and it display above jsp.
I click user link -> then run UserAction.Load()
I click property link -> then run PropertyAction.execute() and error has been shown "UserData has no property thema".
I spy what happened and I notice that I set setAttribute with name "item". So if I use var="item" in my iterator in jsp, it doesn not use value from propertyList but from session !
My question is it is correct behaviour ?
This is defined behavior; whether or not it's "correct" is debatable.
Because you're using JSP EL, the Struts request wrapper is responsible for resolving JSP EL expressions. The normal application scopes are searched first (e.g., application, session, request). If nothing is found, only then will the value stack be queried for matching expressions.
If you accessed item via non-JSP EL means, e.g., the <s:property> tag, only the value stack would be queried, and you'd get the expected behavior.
When you mix ELs results are not always what you'd expect, so you must be aware how the frameworks in question relate to each other.

How to attach for example a #top reference to a <p:commandLink>?

I just wondered how I can attach a reference like a #top to the target action of a commandLink?
Basically in my situation this <p:commandLink> sits in a <p:dataTable> and sets the row-value to the current-Property of a bean:
<p:commandLink ajax="false"
action="#{bean.viewSomePage()}"
value="#{record.name}">
<f:setPropertyActionListener value="#{record}"
target="#{bean.current}" />
</p:commandLink>
In the bean the viewSomePage()-Method just delivers the navigation target:
public String viewSomePage() {
return "index?faces-redirect=true";
}
The address bar of the browser shows then index.xhtml. But how can I achieve that something like index.xhtml#statusis shown?
What I want to do is to link on a specific <p:tab> of a <p:tabView>according to this answer. It is already working, but I am not able to link it through a <p:commandLink>. Of course I already tried to simply attach it in the viewSomePage()-Method, with no success.
Thx for any help!
This isn't supported by JSF navigation handler. Your best bet is manually invoking ExternalContext#redirect() with the desired URL with the desired fragment identifier:
public void viewSomePage() throws IOException {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.redirect(ec.getRequestContextPath() + "/index.xhtml#status");
}
Or if you happen to use JSF utility library OmniFaces already:
public void viewSomePage() throws IOException {
Faces.redirect("index.xhtml#status");
}

How can I check if an object stored with #WindowScoped is stored correctly?

Two days ago I wrote this question:
How can I retrieve an object on #WindowScoped?
and BalusC answered with some suggestions, now I have some problem to understand if my problem is that the object in WindowScoped is stored properly or my code to retrieve it is wrong!
Well, as I said, I have an object that I stored in #WindowScoped annotation but I can retrive this object only the first time! Why?
I just have a doubt: the CODI extension of MyFaces could be configured in some manner? Or I can use it simple adding the jar files to my project?
However, these are parts of my code because I don't know where is the problem:
LogicBean.java (the object that I should retrive):
#ManagedBean (name="logicBean" )
#WindowScoped
public class LogicBean implements Serializable
{
String pageIncluded;
// getter and setter methods
public String action(String value)
{
setPageIncluded(value);
return "include";
}
}
include.xhtml:
<ui:include src="#{logicBean.pageIncluded}"/>
ProgettiController.java
#ManagedBean(name = "progettiController")
#SessionScoped
public class ProgettiController implements Serializable {
private FacesContext context = FacesContext.getCurrentInstance();
private LogicBean logicBean = context.getApplication().evaluateExpressionGet(context, "#{logicBean}", LogicBean.class);
//getter and setter methods
public void testMethod()
{
logicBean.action("WEB-INF/jsf/page1.xhtml");
}
}
I tried also using #ManagedProperty("#{logicBean}") and setting the scope as WindowScoped but nothing change...
EDIT: after some new trials I found a strange problem, on my include.xhtml I added #{progettiController.logicBean.getPageIncluded()} and #{logicBean.getPageIncluded()} for check these two fields o?
Well, when I load the application for the first time the variables are correctly set and I see what I want, the second time the first variable is setted with the new value but the second is empty and I don't see anything, but now is coming the strange thing... if I should try again the app I should open index.xhtml where I had some forms like this:
<h:form>
<h:commandLink action="#{logicBean.action('/WEB-INF/jsf/progetti/List.xhtml')}" value="Show All Progetti Items"/>
</h:form>
and which is the result?
The first variable remains set with the old value (wrong) but the second is setted correctly so I can review the page like I would!
If someone can help me I will thank him/her forever!
CODI is an extension to CDI, so you should manage your beans by CDI #Named annotation instead of the JSF #ManagedBean annotation. Then you can inject the other bean by CDI #Inject annotation. The following example should work:
import javax.inject.Named;
import org.apache.myfaces.extensions.cdi.core.api.scope.conversation.WindowScoped;
#Named
#WindowScoped
public class LogicBean implements Serializable {
// ...
}
and
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;
#Named
#SessionScoped
public class ProgettiController implements Serializable {
#Inject
private LogicBean logicBean;
// ...
}

#ManagedProperty injected AFTER #PostConstruct

THIS PROBLEM IS ALREADY SOLVED IN THE MYFACES 2.1 IMPLEMENTATION
I have a link which passes an Integer parameter properly like this:
<h:link outcome="/process/createProcess">
<f:param name="id" value="#{process.idprocess}" />
Edit
</h:link>
It goes to "createProcess.xhtml?id=21" properly, and I have this code in the request scope backing Bean createProcess:
#ManagedProperty(value="#{param.id}")
private Integer idProcess;
private Process newProcess;
#PostConstruct
public void init()
{
log();
if (idProcess!=null)
newProcess = Dao.getProcessDAO().get(idProcess);
else
newProcess = new Process();
}
I've notice that idProcess is always null. After debugging I realized that setIdProcess method is called AFTER #PostConstruct.
I understand that injection is done just after the construction of the bean and all the managedProperties are available in #PostConstruct.
What am I missing?
Just for reference, I think the issue in this post is MYFACES-3116, with was already fixed at , so 2.0.6, 2.1.0 and upper versions does not have it.

Resources