using JSF EL expression inside web.xml - jsf

Can I use EL expression inside web.xml ?
Like this
Web.xml
<context-param>
<param-name>primefaces.DIR</param-name>
<param-value>#{userUtilityBacking.direction}</param-value>
</context-param>
and my JSF bean like this
JSF bean
#ManagedBean(name="userUtilityBacking")
#SessionScoped
public class UserUtilityBacking implements Serializable {
private static final long serialVersionUID = 1L;
private String direction ;
// and public setters and getter
Will it work ?

Can I use EL expression inside web.xml ?
Not exactly that. By default, the servletcontainer doesn't EL-evaluate the context parameters when the web.xml is been parsed during application startup. However, build tools like Ant and Maven and some servletcontainers like JBoss (after setting a specific configuration setting) support using ${...} syntax similar to EL to inline environment variables and/or VM arguments by their name in several deployment descriptor XML files such as web.xml, ejb-jar.xml and persistence.xml. Note: that are thus not those variables which you've declared in JSF EL scope, such as managed bean.
Will it work ?
It will only work if PrimeFaces gets the static value "#{userUtilityBacking.direction}" as String and then programmatically EL-evaluates it in the current EL context using for example Application#evaluateExpressionGet(). But, based on the PrimeFaces 3.5 source code, it is not doing that anywhere. It look like they implemented it for 4.x only.
In your particular case, you'd better just specify the direction directly on <html> element to apply it document-wide and/or in dir attribute of an arbitrary HTML or JSF component.
<html dir="#{userUtilityBacking.direction}">

Related

View scope: java.io.NotSerializableException: javax.faces.component.html.HtmlInputText

There is an error each time a button calls an action from the backing-bean.
Only applies to beans with a view scope and I haven't found a way to fix it without regression over other modules in the code.
DefaultFacele E Exiting serializeView - Could not serialize state: javax.faces.component.html.HtmlInputText
java.io.NotSerializableException: javax.faces.component.html.HtmlInputText
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
Or also:
com.ibm.ws.webcontainer.servlet.ServletWrapper service SRVE0014E: Uncaught service() exception
root cause Faces Servlet: ServletException: /jspFiles/jsf/Deployments/editQueue.faces No saved view state could be found for the view identifier /jspFiles/jsf/Deployments/editQueue.faces
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:205)
Caused by: javax.faces.application.ViewExpiredException: /jspFiles/jsf/Deployments/editQueue.faces No saved view state could be found for the view identifier: /jspFiles/jsf/Deployments/editQueue.faces
at org.apache.myfaces.lifecycle.RestoreViewExecutor.execute (RestoreViewExecutor.java:128)
faces-config.xml
<managed-bean>
<managed-bean-name>pc_EditQueue</managed-bean-name>
<managed-bean-class>pagecode.jspFiles.jsf.deployments.EditQueue</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
<managed-property>
<property-name>queueDeploymentBean</property-name>
<value>#{queueDeploymentBean}</value>
</managed-property>
</managed-bean>
web.xml
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</param-name>
<param-value>true</param-value>
</context-param>
bean:
#ManagedBean
#ViewScoped
public class EditQueue extends PageCodeBase implements Serializable {
private static final long serialVersionUID = -1L;
public String doButtonAddAction() {
// calls manager (long)
FacesUtil.setViewMapValue("queueDeploymentBean", queueDeploymentBean);
return "";
}
I read this suggestion to set SERIALIZE_STATE_IN_SESSION to false and indeed this solution works for this view scope bean. However this fix comes at a high cost: many existing modules in the application don't work anymore so I cannot use this fix there. Some of the regression observed are:
// returns null must be changed with FacesUtil.getSessionMapValue("userId");
getSessionScope().get("userId");`
// returns null must be changed with FacesUtil.getViewMapValue("linkerBean");
linkerBean = (Linker) getManagedBean("linkerBean");`
// NPE so must be changed with FacesContext.getCurrentInstance().addMessage(...)
getFacesContext().addMessage(...)`
So my questions are:
why the NotSerializableException even though the bean implements Serializable ?
is there a way to apply the SERIALIZE_STATE_IN_SESSION param over only a subset of the beans or not ?
is there another solution to have my view scope bean to work (without having to change them to request scope or else) ?
WebSphere 8.0.0.3,
Java 1.6.0,
JSF 2.0,
RichFaces 4.2.3.Final
why the NotSerializableException even though the bean implements Serializable ?
Not only the bean needs to be serializable, but all of its properties (and all their nested properties etc) must also be serializable. The name of the offending non-serializable class can easily be found in the exception message:
java.io.NotSerializableException: javax.faces.component.html.HtmlInputText
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
This suggests that you're binding a <h:inputText> component to the bean like below:
<h:inputText binding="#{bean.fooInput}" ...>
private UIComponent fooInput;
This is indeed illegal when the bean is not in request scope. UIComponent instances are request scoped and may not be shared across multiple requests. Moreover, UIComponent instances are not serializable. Only their state is, but JSF will worry about that all by itself.
You must remove the fooInput property and you need to look for a different solution for the problem for which you incorrectly thought that binding the component to a view scoped bean would be the right solution.
If you intend to access it elsewhere in the view, e.g. #{bean.fooInput.value}, then just bind it to the Facelet scope without the need for a bean property:
<h:inputText binding="#{fooInput}" ...>
It'll be available elsewhere in the same view via #{fooInput.xxx}.
<h:inputText ... required="#{empty fooInput.value}" />
If you intend to set some component attribute programmatically inside the bean, e.g. fooInput.setStyleClass("someClass"), or fooInput.setDisabled(true), then you should be binding the specific attribute in the view instead of the whole component:
<h:inputText ... styleClass="#{bean.styleClass}" />
...
<h:inputText ... disabled="#{bean.disabled}" />
If you are absolutely positive that you need to get a hand of whole UIComponent instance in the bean for whatever reason, then manually grab it in method local scope instead of binding it:
public void someMethod() {
UIViewRoot view = FacesContext.getCurrentInstance().getViewRoot();
UIComponent fooInput = view.findComponent("formId:fooInputId");
// ...
}
But better ask a question or search for an answer how to solve the concrete problem differently without the need to grab a whole component in the backing bean.
See also:
How does the 'binding' attribute work in JSF? When and how should it be used?
As to the ViewExpiredException, this has different grounds which is further elaborated in javax.faces.application.ViewExpiredException: View could not be restored.

EL expressions in Omnifaces CDN resource handler not resolved in Wildfly 9

I am playing around with new Wildfly 9.0.0.Final. After the deployment of my JSF2.2 web application, the Omnifaces2.1 CDNResourceHandler stopped resolving EL expression.
My definition in web.xml:
<context-param>
<param-name>org.omnifaces.CDN_RESOURCE_HANDLER_URLS</param-name>
<param-value>
styles:*=#{CDNResourcesBean.styles}/*
</param-value>
</context-param>
In .xhtml, style.css file exists in resources of the project structure
<h:outputStylesheet library="styles" name="style.css"/>
Generated HTML:
<link type="text/css" rel="stylesheet" href="/style.css" />
My CDNResourceBean
#Named
#RequestScoped
public class CDNResourcesBean {
public String getStyles() {
return "https://abcdef.cloudfront.net/";
}
From what I see the CDNResourceHandler is called, it replaces links but from unknown reason the El expression #{CDNResourcesBean.styles} is ignored.
How should I make it working? Is that a question of CDI configuration, Bean initialization order, CDNResourceHandler not compatible with new WF?
Technology:
Application server: Wildfly 9.0.0.Final
Omnifaces: 2.1
It's consequence of a bugfix in Weld implementation of WildFly 9. As per issues CDI-525, WELD-1941 and WFLY-4877, the CDI spec appears to be not consistent with JavaBeans specification as to default managed bean name in case the unqualified classname starts with more than two capitals. CDI spec merely stated as below in the spec, while Weld was initially following the JavaBeans specification:
The default name for a managed bean is the unqualified class name of the bean class, after converting the first character to lower case.
Weld was been put back to take it literally. The CDNResourcesBean is now registered as as #{cDNResourcesBean} instead of #{CDNResourcesBean}.
For now, if you intend to follow the JavaBeans specification, then your best bet is to explicitly specify the managed bean name.
#Named("CDNResourcesBean")
#RequestScoped
public class CDNResourcesBean {}
This problem is not related to OmniFaces.
Unrelated to the concrete problem, get rid of the double trailing slash in URL.

#NotNull Bean Validation ignored for viewParam

Problem
I'm trying to validate a mandatory GET request parameter.
In the view I've added a corresponding viewParam tag.
<f:metadata>
<f:viewParam name="customerId" value="#{customerDetailBean.customerId}"/>
</f:metadata>
And my CDI bean looks like this
#Model
public class CustomerDetailBean {
#NotNull
private Integer customerId;
public Integer getCustomerId() {
return customerId;
}
public void setCustomerId(Integer customerId) {
this.customerId = customerId;
}
}
When I use the following request, validation works fine and the expected validation message is displayed.
http://localhost:8080/getsupport/customerdetail.jsf?customerId=
However, when I change the request by removing the parameter customerId, validation is skipped and no message is shown.
http://localhost:8080/getsupport/customerdetail.jsf
Is there a way to make it work as expected?
Workaround
I've changed my viewParam declaration to
<f:metadata>
<f:viewParam name="customerId" value="#{customerDetailBean.customerId}" required="true" />
</f:metadata>
That updated version works fine with the second request. Anyway I would prefer to use bean validation.
My setup
Mojarra JSF 2.2.7
Weld 2.2.1.Final
Hibernate Validator 5.1.1.Final
Tomcat 7.0.54
web.xml
<context-param>
<param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
<param-value>true</param-value>
</context-param>
This is, unfortunately, "working as designed". All validation is skipped when nothing's been submitted. Only the <f:viewParam required> has special treatment. It's also considered when nothing's been submitted. See also UIViewParameter#processValidators() javadoc and source code.
In the Mojarra issue tracker I can only find issue 3058 as a related issue, whereby the <f:validateRequired> isn't being considered. This is technically actually exactly the same problem as you're facing with #NotNull. I've created issue 3339 on this.
In the meanwhile, your best bet is falling back to required="true". A custom component can also, but as far as I see this isn't going to be trivial.
Update: after all, the fix is relatively easy and has been implemented in OmniFaces <o:viewParam> in the current 2.0 snapshot release.
Prior to JSF 2.0, validation was simply not run at all on fields whose values were
empty or null. JSF 2.0 changes this default behavior slightly. If the JSF runtime is executing in
an environment that supports bean validation, empty fields are validated by default. Otherwise,
the behavior is the same as it was prior to JSF 2.0: empty fields are not validated.
Since Tomcat(& Jetty) is not a J2EE compliant server bean validation is not enabled by default. That is the reason why your validation is skipped.
To force JSF to validate empty fields, add this to your web.xml file:
<context-param>
<param-name>javax.faces.VALIDATE_EMPTY_FIELDS</param-name>
<param-value>true</param-value>
</context-param>
The Bean validation(JSR 303) can be configured on non j2ee compliant server with minimal configuartion(I have never configured this :)). In some way you have enabled bean validation and you have not above context param then jsf runtime would consider it as true and validate empty and null fields for validation.
But I suggest to use required attribute which is suggested experts for performance because using annotations invove reflections. So we could avoid for atleast in one case.
And ensure context param javax.faces.validator.DISABLE_DEFAULT_BEAN_VALIDATOR is not set to true in web.xml.
To have a look at list of these parameters see
Overview of all JSF-related web.xml context parameter names and values
Hope this helps.

#Inject-ed value null in #FacesComponent

I have the impression that CDI is not working with classes that have a #javax.faces.component.FacesComponent. Is this true?
Here's my example, that doesn't work. The MyInjectableClass is used at other points in the code where injection is not a problem, so it must be about the #FacesComponent annotation I think.
The class I want to inject:
#Named
#Stateful
public class MyInjectableClass implements Serializable {
private static final long serialVersionUID = 4556482219775071397L;
}
The component which uses that class;
#FacesComponent(value = "mycomponents.mytag")
public class MyComponent extends UIComponentBase implements Serializable {
private static final long serialVersionUID = -5656806814384095309L;
#Inject
protected MyInjectableClass injectedInstance;
#Override
public void encodeBegin(FacesContext context) throws IOException {
/* injectedInstance is null here */
}
}
Unfortunately, even for JSF 2.2 #FacesComponent, #FacesValidator and #FacesConverter are not valid injection targets (read What's new in JSF 2.2? by Arjan Tijms for more details). As Arjan points out:
It’s likely that those will be taken into consideration for JSF 2.3 though.
What can you do for now? Well, you've got basically two choices:
Handle CDI injection via lookup, or switch to EJB and do the simpler EJB lookup;
Annotate tour class with #Named instead of #FacesComponent, #Inject the component the way you did and register your component in faces-config.xml. As the UI component instance is created via JSF Application#createComponent(), not via CDI you will also need a custom Application implementation as well (exactly like OmniFaces has for those converters/validators).
And, by the way, you've got two issues with what you've got this far: (1) what is meant by #Named #Stateful when the former is from a CDI world and the latter is from EJB world and (2) are you sure you intend to keep state in a faces component that's basically recreated on every request?
#FacesCompnent is managed by JSF and injection is not supported into them.
Passing the value in from the XHTML page via a composite component attribute worked for us.

Invoking methods with parameters by EL in JSF 1.2

I am using a datatable and for each row I have two buttons, an "Edit" and a "Delete".
I need these buttons to be read-only, i.e. disabled, if a certain condition is met for the row in question. I have seen in JSF 2 that it is possible to pass parameters to method calls. Is there anything equivalent in JSF 1.2?
Ideally what I would like it something like (the looping variable is loop and there is another bean, helper, which contains the method I would like to invoke):
<h:commandButton value="Edit"
disabled="#{helper.isEditable(loop.id)}" />
In this case it does not make semantic sense to add an isEditable attribute to the bean and it is not practical to create a wrapper Object around the bean.
Thanks in advance.
I have seen in JSF 2 that it is possible to pass parameters to method calls. Is there anything equivalent in JSF 1.2?
Passing parameters to method calls is not specific to JSF 2. It is specific to EL 2.2, which is in turn part of JSP 2.2 / Servlet 3.0 / Java EE 6. JSF 2 just happens to be part of Java EE 6 as well. In other words, if you deploy your JSF 1.2 web application to a Servlet 3.0 compatible container like Tomcat 7, Glassfish 3, etc and your web.xml is declared conform Servlet 3.0 spec version, then it'll just work out the box for JSF 1.x as well.
If you're however still targeting a container of an older Servlet version, then you need to supply a different EL implementation which supports invoking methods with arguments. One of those implementations is JBoss-EL which you can install by just dropping the jboss-el.jar file in /WEB-INF/lib of your webapp and adding the following context parameter to the web.xml. Here's a Mojarra-specific example (Mojarra is the codename of JSF RI):
<context-param>
<param-name>com.sun.faces.expressionFactory</param-name>
<param-value>org.jboss.el.ExpressionFactoryImpl</param-value>
</context-param>
If you're using MyFaces as JSF implementation, you need the following context parameter instead:
<context-param>
<param-name>org.apache.myfaces.EXPRESSION_FACTORY</param-name>
<param-value>org.jboss.el.ExpressionFactoryImpl</param-value>
</context-param>
See also:
Invoke direct methods or methods with arguments / variables / parameters in EL

Resources