Why doesn't JSF 2.0 RI (Mojarra) scan my class' annotations? - jsf

I have a War and Jar project in my Eclipse-based JSF project. I have decided to use annotations to declare my FacesConverter, (among a myriad other things), rather than declare it using my faces-config.xml.
#FacesConverter(value="passwordFieldStringConverter")
public class PasswordFieldStringConverter implements Converter {
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) throws ConverterException {
try {
return arg2.getBytes("UTF-16BE");
}
catch(UnsupportedEncodingException uee) {
Assert.impossibleException(uee);
}
return(null);
}
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) throws ConverterException {
try {
return new String((byte[]) arg2, "UTF-16BE");
}
catch(UnsupportedEncodingException uee) {
Assert.impossibleException(uee);
}
return(null);
}
}
And then I use passwordFieldStringConverter directly in my .xhtml:
<?xml version="1.0" encoding="UTF-8" ?>
<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:sec="http://www.springframework.org/security/facelets/tags">
<ui:composition>
<f:view>
<f:loadBundle basename="landingPage.bundle" var="bundle" />
<ui:decorate template="/WEB-INF/jsf_helpers/htmlShell.xhtml">
<ui:param name="PageTitleParam" value="#{bundle.pageTitle}" />
<h:form>
<h:dataTable var="rowVar" value="#{userListContainer.users}">
<f:facet name="header"><h:outputText value="Users you are currently managing:" /></f:facet>
<h:column>
<f:facet name="header">
<h:outputText value="Screen Name" />
</f:facet>
<h:outputText value="#{rowVar.screenName}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Password" />
</f:facet>
<h:outputText value="#{rowVar.password}">
<f:converter converterId="passwordFieldStringConverter" />
</h:outputText>
</h:column>
</h:dataTable>
</h:form>
</ui:decorate>
</f:view>
</ui:composition>
</html>
JSF is supposed to scan the jars in my War at deployment-time and detect which classes have annotations on them (and auto-configure the application accordingly). My problem is that JSF is apparently not detecting the classes I have which sport annotations.
The War project has all of my .xhtml files as well as the project's faces-config.xml, my Jar project has all of my faces related Java code (action beans, managed beans, custom converters, etc.)

Yes, I'm immediately answering my own question because I already spent a week banging my head on the table and I only figured out my problem after debugging through the JSF 2.0 RI (Mojarra) to see what it was doing.
Basically, the annotation scanner only consults the WAR's /WEB-INF/classes .class files for annotations (assuming you have a faces-config.xml in /WEB-INF). If you keep your code in separate Jar files and want your .class files you have in /WEB-INF/lib .jar files to be scanned for annotations, you must have a faces-config.xml in that Jar's META-INF folder. The faces-config.xml you plop into your jar can be empty, it just needs to be there or else the annotation scanner will passover your jar like it was leftover meatloaf.
Empty faces-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee /WEB-INF/schema/web-facesconfig_2_0.xsd"
version="2.0" metadata-complete="false">
<!-- This file must be present with our jar, even if it is empty. Otherwise, our Java annotations won't get scanned! -->
</faces-config>
I know a threw out a lot of -INF's there. So, just to recap. Your faces-config.xml in your War goes in WEB-INF. Your potentially empty, annotation scanner enabling, faces-config.xml in each of your Jar files goes in that Jar's META-INF.
If you're wondering why the behavior has to be so nutty, it's because the JSF configs can be decentralized and scattered across 1st and 3rd party libraries this way. And if you're wondering about the whole presence of the faces-config.xml in a jar being a factor, well, my opinion is that that is what marks a Jar as interesting to the engine - and the absence of a faces-config.xml means the annotation scanner can avoid that jar and save on processing at deployment time. It just would have been nice if those scanner semantics were a little more clearly explained somewhere, <expletives deleted>!
The following blog post was very useful in my understanding of what the code was doing:
http://one-size-doesnt-fit-all.blogspot.com/2007/01/using-multiple-faces-configxml-files-in.html
I really hope this saves someone from a week of pain like I had.

A JAR contains both EJB & FacesBeans:
In the case that the JAR that contains Faces Beans is already bundled in an ear (because it contains EJBs), then you also have to put the same JAR in the WEB-INF/lib of the war (on top of adding the faces-config.xml in the META-INF directory), so that the container recognizes the JSF 2.0 Annotations.
In this case, it is probably better to create two JARS, one for the EJBs and one for the FacesBeans.

Related

How to integrate Hibernate Validator into Tomcat 7?

I've successfully integrated JSF (Mojarra) and CDI (Weld), but can't get Hibernate Validator to work.
The following jars are added to WEB-INF/lib:
validation-api-1.1.0.Final.jar
hibernate-validator-5.1.0.Final.jar
jboss-logging-3.1.3.GA.jar
classmate-1.0.0.jar
Tomcat 7 comes with EL 2.2 jars so I didn't add them.
My JSF page:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Test</title>
</h:head>
<h:body>
<h:form>
<h1><h:outputText id="hello" value="Hello, #{testController.name}!"/></h1>
<p:inputText id="name" value="#{testController.name}"/>
<h:message id="error" for="name"/>
<h:commandButton value="Change Name">
<f:ajax execute="name" render="hello error"/>
</h:commandButton>
</h:form>
</h:body>
</html>
And my backing bean:
#Named
#ApplicationScoped
public class TestController {
#NotNull
#Size(min = 3, max = 5)
private String name;
#PostConstruct
private void init() {
name = "Bill";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
It's expected that when the size of the name is smaller than 3 or bigger than 5, an error message is shown, but it turns out to be not. Seems the Hibernate Validator is not working . I did see it's detected but was no longer logged:
Mar 11, 2014 9:31:40 PM org.hibernate.validator.internal.util.Version <clinit>
INFO: HV000001: Hibernate Validator 5.1.0.Final
Is there anything wrong?
Update
Finally I figured out it's a Mojarra regression. The Hibernate Validator works now with MyFaces.
Just to avoid confusion (as I have been confused, looking for the error despite it had already been solved because I didn't see the update section at the end of the post), let me add the answer on behalf of the OP:
It seems the OP used a Mojarra version that was broken. They solved the problem by migrating to MyFaces (see the update to their question). FWIW, I tried their example using Mojarra 2.2.12, and it worked fine.
When you say you integrated with Tomcat 7, how did you do that? There is some glue code in application servers which make sure that for example the ValidatorFactory is visible to JSF. Not sure whether something like this would be required for you as well.
Have you enabled debug/trace logging to verify whether Validator bootstraps or get called?
Also you could try to add to the JSF page, but this should be optional.
Aren't you missing the <f:validateBean> tag on the page? I think you might also need to call the Validator.validate(bean) method in order to get it to fire.

How to form #Named Backing Bean in JSF

I read somewhere that it's better to use CDI #Named instead of JSF #ManagedBean, because of CDI, so I'm trying to convert some of my code.
I'm trying to use #Named in JSF, but it's always unreachable.
When using #ManagedBean there was no problem.
I'm using it like #ManagedBean, as below
CustomerBacking.java
package com.wordpress.marczykm.backing;
import javax.ejb.EJB;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
#Named("customer")
#RequestScoped
public class CustomerBacking {
#EJB
private CustomerService customerService;
public CustomerBacking() {
}
public String addCustomer(Customer customer) {
customerService.addCustomer(customer);
return "customer_overview";
}
public Customer getCustomer(){
return customerService.getCustomer();
}
}
index.xhtml
<!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://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>EJB 3.0 Test</title>
</h:head>
<h:body>
<h:outputText value="#{customer.firstname}"/>
<h:form>
<h:outputText value="ImiÄ™"/>
<h:inputText id="firstname" name="firstname" value="#{customer.firstname}" /><br/>
<h:outputText value="Nazwisko"/>
<h:inputText id="lastname" name="lastname" value="#{customer.lastname}" /><br/>
<h:commandButton value="Dodaj" actionListener="#{customer.addCustomer}"/>
</h:form>
</h:body>
</html>
To sum up, looking at Netbeans sample CDI app, the bean which needs to be accesible by JSF page needs to:
have #Named annotation (javax.inject.Named)
have scope annotation (like #SessionScoped, #RequestScoped, #ViewScoped), but imported from javax.enterprise.context.*
doesn't have to have empty, non-argument constructor
and the thing that wasn't in my code is that, that the bean needs to implement Serializable (java.io.Serializable)
last thing is that if your app is a web application it needs a beans.xml (can be completly empty) in WEB-INF directory, if it is a bean app it have to be in META-INF directory
You don't mention which servlet container/application server and which CDI implementation version you're using.
I have no clue what Spring Tool Suite assumes as default, presumably it's Tomcat, Spring and no CDI at all, so you have to add and configure a CDI implementation (e.g. Weld or OpenWebBeans).
For CDI 1.0, you'll have to add a WEB-INF/beans.xml descriptor (which may be empty) to have your beans discovered. This is no longer necesary for CDI 1.1.

Why <f:validateBean /> won't work?

I use JSF 2.0, hibernate-validator4.2.jar validation-api.jar tomcat and Eclipse.
I put #Size(min=3, message="xxx") annotation in a #ManagedBean and <f:validateBean /> between <h:inputText value="#{user.name}"></h:inputText>
When I try to run the project i get this error...
exception
javax.servlet.ServletException: Expression Error: Named Object: javax.faces.Bean not found.
javax.faces.webapp.FacesServlet.service(FacesServlet.java:606)
root cause
javax.faces.FacesException: Expression Error: Named Object: javax.faces.Bean not found.
com.sun.faces.application.ApplicationImpl.createValidator(ApplicationImpl.java:1593)
com.sun.faces.facelets.tag.jsf.ValidatorTagHandlerDelegateImpl.createValidator(ValidatorTagHandlerDelegateImpl.java:244)
com.sun.faces.facelets.tag.jsf.ValidatorTagHandlerDelegateImpl.applyAttachedObject(ValidatorTagHandlerDelegateImpl.java:132)
com.sun.faces.facelets.tag.jsf.ValidatorTagHandlerDelegateImpl.applyNested(ValidatorTagHandlerDelegateImpl.java:211)
com.sun.faces.facelets.tag.jsf.ValidatorTagHandlerDelegateImpl.apply(ValidatorTagHandlerDelegateImpl.java:87)
javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
why? (this only appears when i put tag)
User.java
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.validation.constraints.Size;
#ManagedBean(name="user")
#SessionScoped
public class User{
#Size(min=3, message="At least 3 characters!")
private String name;
public String getName() {
return nume;
}
public void setName(String name){
this.name=name;
}
}
adduser.xhtml
<!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://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<ui:composition template="/templates/master_layout.xhtml">
<ui:define name="text_header" >Panou de control: Adauga user </ui:define>
<ui:define name="content">
<h:panelGrid columns="3">
<h:outputText value="Name"></h:outputText>
<h:inputText value="#{user.name}">
<f:validateBean />
</h:inputText>
<h:commandButton value="Inregistreaza" action="index.xhtml"></h:commandButton>
</h:panelGrid>
</ui:define>
</ui:composition>
</html>
It should work perfectly fine, although the empty <f:validateBean/> tag is entirely superfluous in this context. It's supposed to be used to "finetune" validation more, such as grouping of validation and/or disabling the implicit bean validation on a per-input basis by specifying the desired tag attributes. You have however no attributes on that tag, so just remove that tag altogether. On a default JSF 2 + JSR 303 project setup, it's supposed to kick in fully transparently without adding more JSF tags whenever there's a JSR 303 annotation on the property such as #Size and likes.
But I don't think that removing the tag will solve this particular exception. Your problem lies thus deeper. This validator is supposed to be auto-registered on startup. However, the exception basically tells that the validator is not registered at all. With the information given so far, it's not possible to give a targeted answer. I can think of the following possible causes:
There's a bug in the JSF implementation which you're using. Upgrade it to a newer version.
You have multiple JSF libraries of different versions in your classpath. Cleanup it.
The faces-config.xml root declaration is not declared conform JSF 2.x. Fix it.

How to see message.properties in a Jar using JSF?

Using: JSF 1.2, Facelets 1.1.15, GateIn 3.1 GA, Richfaces 3.3.3
I have some common .xhtml and backing bean in a JAR that our portlets can see. I did this by overriding ResourceResolver as described in other posts:
http://ocpsoft.com/opensource/create-common-facelets-jar/
How to use Facelets composition with files from another context
The portlets can load the XHTML and use the backing bean.
Here is my problem: I cannot get the xhtml to substitute the messages defined in messages_en.properties. I have tried moving the properties file outside of the JAR and placing directly in /lib folder. I have also tried putting a / in front of the name to try to get the resolver to find it. I have also put it in the components folder.
The common jar info is: I hava a my-portlet-common-resources.jar which resides in server/my-portal/lib. The jar is structured like so:
com/portlet/common/CustomResourceResolver.class
com/portlet/common/FilterCreateBean.class - backing bean for the common popup
messages_en.properties
faces-config.xml
META-INF/components/commonPopups.xhtml
META-INF/faces-config.xml - declares the FilterBean
META-INF/Manifest.mf
faces-config.xml contents:
<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
version="1.2">
<application>
<locale-config>
<default-locale>en</default-locale>
</locale-config>
<message-bundle>/messages_en.properties</message-bundle>
</application>
<managed-bean>
<managed-bean-name>FilterCreateBean</managed-bean-name>
<managed-bean-class>com.portlet.common.FilterCreateBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>
Include the messages in commonPopups.xhtml (partial snip):
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<a4j:loadBundle basename="messages" var="msgs"/>
<rich:panel style="border-style:none;" id="addNewChainPanel">
<rich:modalPanel id="modalNewChainPanel" autosized="true">
<f:facet name="header"><h:outputText value="#{msgs['filterset.modal.new.title']}" /></f:facet>
</ui:composition>
This should work. Perhaps you already have a messages*.properties file in the classpath root of your main webapp. This one has then precedence in classloading. You need to put it in a more specific package. Put the JAR's one in for example the com/portlet/common folder so that it becomes member of the com.portlet.common package. This way it'll be available by:
<a4j:loadBundle basename="com.portlet.common.messages" var="msgs"/>
Unrelated to the concrete problem, the <message-bundle> entry in faces-config.xml has a completely different purpose. It's supposed to override JSF default validation/conversion messages which are returned by JSF default validators/converters. It is not intended to provide localized content. There you use the <resource-bundle> entry or <xxx:loadBundle> tag for. I'd remove that entry from the faces-config.xml.

JSF 2.0 ViewScoped life cycle

My problem is that one of my ViewScoped bean is created several time within the same view. The constructor of ViewScopedBean is created every time I select a node in the tree.
<h:form>
<p:tree value="#{treeBean.root}" var="node"
selectionMode="single" selection="#{viewScopedBean.selectedNode}">
<p:ajax event="select" update="selectedNode, treeBeanUpdate, otherBeanUpdate, panel" listener="#{treeBean.onNodeSelect}" />
<p:treeNode>
<h:outputText value="#{node}" />
</p:treeNode>
</p:tree>
Selected Node: <h:outputText value="#{viewScopedBean.selectedNode}" id="selectedNode"/><br/>
Current TreeBean: <h:outputText value="#{treeBean}" id="treeBeanUpdate"/><br/>
Current OtherBean: <h:outputText value="#{viewScopedBean}" id="otherBeanUpdate"/><br/>
<p:outputPanel id="panel">
<ag:profileComponent managedBean="#{viewScopedBean.profileBean}"/>
</p:outputPanel>
</h:form>
If I remove this part (reference to a composite component), the constructor of ViewScopedBean is not called:
<p:outputPanel id="panel">
<ag:profileComponent managedBean="#{viewScopedBean.profileBean}"/>
</p:outputPanel>
All the beans used are set as #ViewScoped.
#ManagedBean
#ViewScoped
public class ViewScopedBean implements Serializable {
private TreeNode selectedNode;
private ProfileBean profileBean;
public ViewScopedBean() {
System.out.println("Constructor of ViewScopedBean " + this);
}
#PostConstruct
public void init() {
System.out.println("ViewScoped init" + this);
profileBean = new ProfileBean();
}
}
Is it the correct behaviour? If not what can cause it?
Update: I tried to use an empty composite, and I have the same problem.
<?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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
<composite:attribute name="managedBean" required="true"/>
</composite:interface>
<composite:implementation>
</composite:implementation>
</html>
But if I made the managedBean not required, that's fine.
Another thing I don't get is when the constructor is called, it seems that the object created is not used.
Initiating the view (console output):
Constructor of ViewScopedBean xxx.bean.ViewScopedBean#4e1d2b8e
2 clicks on the tree:
Constructor of ViewScopedBean xxx.bean.ViewScopedBean#4eb64f2e
Constructor of ViewScopedBean xxx.bean.ViewScopedBean#66863941
Then I open the debug window <ui:debug/>, the viewScopedBean is set to xxx.bean.ViewScopedBean#4e1d2b8e
The view scoped bean will be recreated on every request from/to the same view, when you use JSTL tags like <c:if>, <c:forEach> and so on in the view, or when you bind a JSF component as a property of the view scoped bean using binding attribute. That's apparently what's happening in your composite component.
You need to rewrite your composite component as such that it does not utilize any JSTL tags. Binding some JSF component as a property of the bean can also be avoided in many ways, but if that is really not avoidable, then disabling the partial state saving in web.xml should work in most of the cases:
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
If that doesn't work for you, then you really have to share your composite component implementation code with us so that we can point out the caveats and propose the right approaches.

Resources