#ManagedProperty injected AFTER #PostConstruct - jsf-2

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.

Related

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");
}

Setter of h:selectOneMenu is not invoked [duplicate]

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);

jsf 2 managedproperty annotation and parameters

I'm using JSF 2 and Sprig 3, and I want to migrate from using faces-config.xml to annotations.
old one : faces-config.xml :
<managed-bean>
<managed-bean-name>banqueBean</managed-bean-name>
<managed-bean-class>commun.BanqueBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>banqueService</property-name>
<value>#{banqueService}</value>
</managed-property>
<managed-property>
<property-name>banqueId</property-name>
<value>#{param.banqueId}</value>
</managed-property>
</managed-bean>
new one :
public class BanqueBean{
private Banque banque;
#ManagedProperty(name = "banqueService", value = "#{banqueService}")
private BanqueService banqueService;
#ManagedProperty(value = "#{param.banqueId}")
private String banqueId;
// setters for banqueService and banqueId
the value of banqueId is set using :
<f:param value="#{banque.id}" name="banqueId" />
the problem is that when using faces-config.xml the "System" calls the setter of banqueService before the setter of parameter banqueId so that I can use banqueService inside setBanqueId method.
when using annotations it calls the setter of banqueId before banqueService so that I get null as a value of it.
why it inverses the call of this tow methods?
You should not rely on managed property setter method invocation order at all. This is nowhere definied in the specification.
Just hook at that point when JSF is finished with setting of all managed properties. That's the #PostConstruct annotated method.
#PostConstruct
public void init() {
banque = banqueService.find(banqueId);
}
Stop doing business logic in setters, this is only necessary if you're still using legacy JSF 1.1 which didn't support #PostConstruct.
Unrelated to the concrete problem, are you aware of the new JSF2 <f:viewParam>? It might as well help you to get rid of this boilerplate in the bean and end up having only a Banque property and a reusable Converter.
See also:
ViewParam vs #ManagedProperty(value = "#{param.id}")

CDI Injection into a FacesConverter

From just a few searches, this seems like a problem that has been around for a while. I have written a FacesConverter that looks like the following. The object Category is a JPA entity and CategoryControl is the DAO that fetches it.
#FacesConverter(value = "categoryConverter")
public class CategoryConverter implements Converter {
#Inject private CategoryControl cc;
public CategoryConverter() { }
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (cc != null) return cc.getByName(value);
System.out.println("CategoryConverter().getAsObject(): no injection!");
return null;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (!(value instanceof Category)) return null;
return ((Category) value).getName();
}
}
As you probably guessed by now, I never get the injection. I got this workaround from this page, which looks like this.:
Workaround for this problem: create this method in your localeController:
public Converter getConverter()
{
return FacesContext.getCurrentInstance().getApplication().createConverter("localeConverter");
}
and use converter="#{localeController.converter}" in your h:selectOneMenu.
However I can't make this work either. My backing bean creates and returns a converter all right, but it doesn't get the object injected into it.
I am using MyFaces CODI 1.0.1. With the current GlassFish/Weld container. Can anyone suggest a solution before I re-code to not use a Converter?
Replace
#FacesConverter(value = "categoryConverter")
by
#Named
and use
<h:inputSomething converter="#{categoryConverter}" />
or
<f:converter binding="#{categoryConverter}" />
instead of
<h:inputSomething converter="categoryConverter" />
or
<f:converter converterId="categoryConverter" />
By the way, similar problem exist for #EJB inside a #FacesConverter. It however offers a way to be grabbed by JNDI manually. See also Communication in JSF 2.0 - Getting an EJB in #FacesConverter and #FacesValidator. This way you can use a #FacesConverter(forClass=Category.class) without manually defining it everytime. Unfortunately I can't tell from top of head how to realize that for CDI beans.
Update: if you happen to use JSF utility library OmniFaces, since version 1.6 is adds transparent support for using #Inject and #EJB in a #FacesConverter class without any additional configuration or annotations. See also the CDI #FacesConverter showcase example.
The #Inject Annotation only works in CDI managed instances. If you want to use CDI features inside a non-CDI managed instance (Like a JSF Validator or a JSF Converter) you can just programm against the CDI API.
This works only in at least Java EE 7 + CDI 1.1 server.
#FacesValidator("userNameValidator")
public class UserNameValidator implements Validator {
private UserService userService;
public UserNameValidator(){
this.userService = CDI.current().select(UserService.class).get();
}
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
....
}
}
https://docs.oracle.com/javaee/7/api/javax/enterprise/inject/spi/CDI.html
With all the AnnotationHell in Java EE people forget how to code.
Just use #Advanced of CODI for your #FacesConverter see the Wiki.
As soon as a converter or a validator is annotated with #Advanced it's possible to use #Inject.
Per BalusC's answer here, I decided to add JSF (requestscoped) managed beans that only contained #FacesConverter and Converter to resolve this issue in my app, since I'm migrating from JSF managed beans to CDI managed beans.
I tried CODI #Advanced against #FacesConverter, but it does not inject the bean at all.

Injecting Resources Into UIComponent (aka does CDI work here?)

I am writing a (composite) component that needs to interact with my DAO. Here is how the Java part is declared:
#FacesComponent(value="selectLocation")
public class SelectLocation extends UINamingContainer {
To get the DAO object, I tried the CDI annotation:
#Inject private LocationControl lc;
And that didn't work so I tried the Faces annotation:
#ManagedProperty (value = "#{locationControl}") private LocationControl lc;
Both cases nothing happens -- the property lc ends up as null after the constructor finishes.
I use CDI in all my backing beans and it all works. This would be using Weld inside GlassFish 3.1.1. Any suggestions on how to get the resource?
I have a work-around for now, which is to basically put in the boiler-plate code that CDI et. al. is supposed to do away with. I now have this method:
public LocationControl getLocationControl() {
if (lc != null) return lc;
FacesContext fc = getFacesContext();
Object obj = fc.getApplication().evaluateExpressionGet(fc, "#{locationControl}", LocationControl.class);
if (obj instanceof LocationControl) lc = (LocationControl) obj;
return lc;
}
I would like to know if anyone has a better solution.
I don't know if it also works for components, but with CDI + MyFaces CODI you have #Advanced to mark e.g. Phase-Listeners which should be able to use #Inject. If it doesn't work, you could create a feature request in their JIRA. They are pretty fast and there are frequent releases.
Or you use:
MyBean myBean = BeanManagerProvider.getInstance().getContextualReference(MyBean.class);
manually.
There is a way to do this work without workarounds?
Yes, just use a backing bean the usual way.
<x:someComponent value="#{someBean.someProperty}" />
Wrap if necessary in a reusable tagfile/composite to keep it DRY:
<my:someComponent />

Resources