communication in jsf 2.0

34
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API Friday, September 16, 2011 Communication in JSF 2.0 Fast menu Introduction We assume that you're familiar with JSF basics. We assume that you're able to create JSF forms and beans like as demonstrated in the JSF 2.0 tutorial of this blog (model, view and controller). We assume that you've configured JSF to interpret empty string submitted values as null by the following context parameter in web.xml: <context-param> <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name> <param-value>true</param-value> </context-param> The above will prevent that model values get littered with empty strings when the enduser leaves input fields empty. If you're running Tomcat or a clone/fork of it (e.g. JBoss AS, WebSphere AS, etc) or at least a servletcontainer which utilizes Apache EL parser, then we also assume that you've the following startup VM argument set: -Dorg.apache.el.parser.COERCE_TO_ZERO=false This will prevent that the aforementioned context parameter will fail for primitive wrapper managed bean properties (e.g. Long, Integer, Double, Boolean, etc), because this EL parser would immediately coerce an empty string to the wrapped primitive's default value such as 0, 0.0 or false before returning the value to JSF. Glassfish for example does not have this problem. The code examples throughout the article are wherever applicable created and tested on Mojarra 2.1.3 and Glassfish 3.1.1. They should work equally good on older or newer versions or different implementations of JSF 2.x (MyFaces, for example) and/or servlet containers (Tomcat, JBoss, etc), unless explicitly otherwise mentioned. Any error/exception message examples are Mojarra 2.1.3 specific and may (slightly) differ on different versions and implementations. The difference between JSF 2.0 and JSF 2.1 is subtle. As to compatibility, it's important to know that JSF 2.1 is targeted on Servlet 3.0 containers (Glassfish 3, Tomcat 7, JBoss AS 6, etc), while JSF 2.0 is targeted on older Servlet 2.5 containers (Glassfish 2, Tomcat 6, JBoss AS 5, etc). Most notable is Mojarra version 2.1.0; this version does not work on Tomcat/Jetty due to a major bug in the annotation scanner. This has been fixed in Mojarra 2.1.1. Back to top Managed bean names ABOUT BAUKE SCHOLTZ View my complete profile DONATE For the ones who want to express their excessive thanks for my work, I used to have an Amazon wishlist linked on my stackoverflow.com profile, but they unfortunately don't send anything else than books to Curaçao and right now I don't have any interesting books on the list anymore (to anyone who've sent books before: thank you very much, I got 6 books in 6 months). You can always donate something so that I can use it for other stuff which Amazon doesn't send, such as Nespresso coffee. TAGS ActionListener Ajax Authentication CDI Communication Composite Component Converter CSV Custom Component DAO DataTable Design Patterns Download File DTO Dutch Eclipse EJB Exception-Handling Facelets Filter Focus Glassfish Highlight HTML5 i18n Immediate Include JavaScript JDBC JPA JSF JSF2 JSP Managed Bean Messages MySQL OmniFaces Performance PhaseListener POST-Redirect-GET PrimeFaces Rant Renderer SelectBooleanCheckbox SelectOneMenu Servlet Shiro The BalusC Code Code depot of a Java EE developer ► JSF ► JSF Managed Bean ► JSF Web App ► Communication

Upload: nwwar

Post on 27-Oct-2015

142 views

Category:

Documents


3 download

DESCRIPTION

jsf

TRANSCRIPT

Page 1: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

Friday, September 16, 2011

Communication in JSF 2.0

Fas t menu

IntroductionWe assume that you're familiar with JSF basics. We assume that you're able to create JSF forms and beans like as demonstrated inthe JSF 2.0 tutorial of this blog (model, view and controller). We assume that you've configured JSF to interpret empty string submittedvalues as null by the following context parameter in web.xml:

<context-param> <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name> <param-value>true</param-value> </context-param>

The above will prevent that model values get littered with empty strings when the enduser leaves input fields empty. If you're runningTomcat or a clone/fork of it (e.g. JBoss AS, WebSphere AS, etc) or at least a servletcontainer which utilizes Apache EL parser, then wealso assume that you've the following startup VM argument set:

-Dorg.apache.el.parser.COERCE_TO_ZERO=false

This will prevent that the aforementioned context parameter will fail for primitive wrapper managed bean properties (e.g. Long,Integer, Double, Boolean, etc), because this EL parser would immediately coerce an empty string to the wrapped primitive's defaultvalue such as 0, 0.0 or false before returning the value to JSF. Glassfish for example does not have this problem.

The code examples throughout the article are wherever applicable created and tested on Mojarra 2.1.3 and Glassfish 3.1.1. Theyshould work equally good on older or newer versions or different implementations of JSF 2.x (MyFaces, for example) and/or servletcontainers (Tomcat, JBoss, etc), unless explicitly otherwise mentioned. Any error/exception message examples are Mojarra 2.1.3specific and may (slightly) differ on different versions and implementations.

The difference between JSF 2.0 and JSF 2.1 is subtle. As to compatibility, it's important to know that JSF 2.1 is targeted on Servlet 3.0containers (Glassfish 3, Tomcat 7, JBoss AS 6, etc), while JSF 2.0 is targeted on older Servlet 2.5 containers (Glassfish 2, Tomcat 6,JBoss AS 5, etc). Most notable is Mojarra version 2.1.0; this version does not work on Tomcat/Jetty due to a major bug in the annotationscanner. This has been fixed in Mojarra 2.1.1.

Back to top

Managed bean names

ABOUT

BAUKE SCHOLTZ

View my complete profile

DONATE

For the ones who want to express theirexcessive thanks for my work, I used to havean Amazon wishlist linked on mystackoverflow.com profile, but theyunfortunately don't send anything else thanbooks to Curaçao and right now I don't haveany interesting books on the list anymore (toanyone who've sent books before: thank youvery much, I got 6 books in 6 months). Youcan always donate something so that I canuse it for other stuff which Amazon doesn'tsend, such as Nespresso coffee.

TAGS

ActionListener Ajax Authentication CDICommunication Composite ComponentConverter CSV Custom ComponentDAO DataTable Design PatternsDownload File DTO DutchEclipse EJB Exception-Handling

Facelets Filter Focus GlassfishHighlight HTML5 i18n ImmediateInclude JavaScript JDBC JPA

JSF JSF2 JSPManaged Bean Messages

MySQL OmniFacesPerformance PhaseListener

POST-Redirect-GET PrimeFaces RantRenderer SelectBooleanCheckbox

SelectOneMenu Servlet Shiro

T he BalusC CodeCo d e d e p o t o f a Ja va EE d e ve l o p e r

► JSF ► JSF Managed Bean ► JSF Web App ► Communication

Page 2: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

You probably already know that you can annotate backing beans as managed bean with @ManagedBean and specify the managedbean name by the name attribute of the annotation without the need to specify them as <managed-bean> boilerplate in faces-config.xml.

package com.example.controller;

import javax.faces.bean.ManagedBean;import javax.faces.bean.RequestScoped;

@ManagedBean(name="bean")@RequestScopedpublic class Bean {

// ...

}

This way the managed bean is available in EL by #{bean}. But do you also know that JSF will already implicitly use the bean's namewith 1st character lowercased (at least, conform the property naming as stated in the Javabeans specification) when you omit the nameattribute altogether?

package com.example.controller;

import javax.faces.bean.ManagedBean;import javax.faces.bean.RequestScoped;

@ManagedBean@RequestScopedpublic class Bean {

// ...

}

Make use of it and don't repeat yourself!

Back to top

Managed bean naming conventionsAs to naming conventions, there is no strict convention specified by JSF itself. I've seen the following conventions:

Foo

FooBean

FooBacking

FooManager

FooController

FooBackingBean

FooManagedBean

FooBB

SelectOneMenu Servlet Shiro

StackOverflow TabbedPanelTomahawk Tomcat TutorialUnicode Upload File UseBean

Utility ValidatorValueChangeListener Vdldoc

ViewScoped Whitespace ZEEF

ARTICLES

► 3000 (1)► 2013 (6)► 2012 (12)▼ 2011 (2)

▼ September (1)Communication in JSF 2.0

► January (1)

► 2010 (10)► 2009 (7)► 2008 (7)► 2007 (19)► 2006 (22)

FAVORITES

High Quality JSF linksUse the right keywordsHow to write good codeHow to write bad codeJava SE 7.0 API documentationJava EE 6.0 API documentationServlet 3.0 specification (JSR315)JSP/EL 2.2 specification (JSR245)JSP/Servlet tutorials on CoreservletsJSTL 1.2 specification (JSR052)JSTL 1.1 TLD documentationJSF RI (Mojarra) home pageJSF 2.0 specification (JSR314)JSF 2.0 PDL documentationJSF 2.1 VDL documentationJSF tutorial (Java EE tutorial part II chpt 4and on)JSF tutorials on CoreservletsJSF 2.0: The Complete Reference (book)Eclipse IDE for Java EE developers

Page 3: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

FooMB

FooBean is too vague. Really a lot of classes can be marked as javabeans. JSF managed beans, JPA entities, EJBs, service classes,data transfer objects, value objects, etc. The Bean suffix does not indicate the real responsibility of the class in any way. True, I useoften MyBean or Bean in my generic code examples in blogs or forum/Q&A answers, but in real world you should avoid that.

FooManagedBean is a poor name, it's not only too long and ugly, but technically, a managed bean is an instance of a backing beanwhich is managed by some framework (JSF in this case). In JSF, the class definition itself is really a backing bean, not a managedbean. So a FooBackingBean is technically more correct, but it's still too long and the Bean part is still itchy.

FooBB and FooMB are not clear enough and those abbreviations "BB" and "MB" are unlike e.g. "EJB" and "JPA" nowhere mentioned inthe official Java EE documents. This convention should be avoided.

Left behind the Foo, FooBacking, FooManager and FooController. In large projects, I personally tend to use "Manager" for sessionand application scoped beans which are not tied to any input forms and "Backing" for request and view scoped beans which are tied toinput forms. Or if you have a relatively small project, then you could use "Controller" for all beans or even leave it entirely out.

In any way, this is a pretty subjective question which can hardly be answered objectively with The One And Correct answer. It reallydoesn't matter that much to me or anyone else what you makes of it, as long as you're consistent with it throughout the entire project.Consistency is next to self-document-ability a very important aspect in a project.

Back to top

Managed bean scopesJSF2 offers six predefinied @ManagedBean scopes. Their lifetime and use are described in detail below:

@RequestScoped: a bean in this scope lives as long as the HTTP request-response lives. It get created upon a HTTP requestand get destroyed when the HTTP response associated with the HTTP request is finished (this also applies to ajax requests!).JSF stores the bean as an attribute of HttpServletRequest with the managed bean name as key. It is also available byExternalContext#getRequestMap(). Use this scope for pure request-scoped data. For example, plain vanilla GET requestswhich should present some dynamic data to the enduser depending on the parameters. You can also use this scope forsimple non-ajax forms which do not require any model state during processing.

@ViewScoped: a bean in this scope lives as long as you're interacting with the same JSF view in the browser window/tab. It getcreated upon a HTTP request and get destroyed once you postback to a different view. It doesn't immediately get destroyedwhen you leave/close the view by a GET request, but it is not accessible the usual way anymore. JSF stores the bean in theUIViewRoot#getViewMap() with the managed bean name as key, which is in turn stored in the session. You need to returnnull or void from action (listener) methods to keep the bean alive. Use this scope for more complex forms which use ajax,data tables and/or several rendered/disabled attributes whose state needs to be retained in the subsequent requests withinthe same browser window/tab (view).

@SessionScoped: a bean in this scope lives as long as the HTTP session lives. It get created upon the first HTTP requestinvolving this bean in the session and get destroyed when the HTTP session is invalidated (or when you manually remove thebean from the session map). JSF stores the bean as an attribute of HttpSession with the managed bean name as key. It isalso available by ExternalContext#getSessionMap(). Use this scope for pure session-scoped data which can safely beshared among all browser windows/tabs (views) within the same session. For example, the logged-in user, the userpreferences such as user-specific settings and the chosen language/locale, etc.

@ApplicationScoped: a bean in this scope lives as long as the web application lives. It get created upon the first HTTPrequest involving this bean in the application (or when the web application starts up and the eager=true attribute is set in

Eclipse IDE for Java EE developersEclipse Video TutorialsJBoss Tools for EclipseHTML Doctype explained

FOLLOWERS

Join this sitew ith Google Friend Connect

Members (691) More »

Already a member? Sign in

Page 4: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

@ManagedBean) and get destroyed when the web application shuts down (or when you manually remove the bean from theapplication map). JSF stores the bean as an attribute of the ServletContext with the managed bean name as key. It is alsoavailable by ExternalContext#getApplicationMap(). Use this scope for pure application-scoped data which can safely beshared among all sessions. For example, constants such as country codes, static dropdown values, web application specificsettings, etc.

@NoneScoped: a bean in this scope lives as long as a single EL evaluation. It get created upon an EL evaluation and getdestroyed immediately after the EL evaluation. JSF does not store the bean anywhere. So if you have for example three#{bean.someProperty} expressions in your view, then the bean get effectively created three times. Use this scope for a databean which is purely supposed to be injected in another bean of a definied scope. The injected bean will then live as long asthe acceptor bean.

@CustomScoped: a bean in this scope lives as long as the bean's entry in the custom Map which is created for this scope lives.You need to create and prepare this Map yourself in a broader scope, for example the session scope. You need to control theremoval of the bean from the Map yourself. Use this scope if no one of the other scopes suits the requirement, for example aconservation scope which spans across multiple views.

Choose the right scope for the data the bean holds! Abusing an application scoped bean for session/view/request scoped data wouldmake it to be shared among all users, so anyone else can see each other's data which is just plain wrong. Abusing a session scopedbean for view/request scoped data would make it to be shared among all tabs/windows in a single browser session, so the endusermay experience inconsitenties when interacting with every view after switching between tabs which is bad for user experience. If thebean contains a mix of for example request-scoped and session-scoped data, then you should really split the beans in two differentscoped beans. They can interact with each other by @ManagedProperty. See also the next chapter.

Back to top

Injecting managed beans in each otherYou can use @ManagedProperty to inject among others @ManagedBean instances in each other. This is particularly useful if you havea request or view scoped bean associated with a page/form and would like to have instant access to a session or application scopedbean. For example, to get the currently logged-in user which is hold in a session scoped managed bean so that you can performactions based on the currently logged-in user.

Here's the session scoped one:

package com.example.controller;

import java.io.Serializable;

import javax.faces.bean.ManagedBean;import javax.faces.bean.SessionScoped;

@ManagedBean@SessionScopedpublic class ActiveUser implements Serializable {

// ...

}

Here's the view scoped one:

package com.example.controller;

Page 5: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

package com.example.controller;

import java.io.Serializable;

import javax.faces.bean.ManagedBean;import javax.faces.bean.ManagedProperty;import javax.faces.bean.ViewScoped;

@ManagedBean@ViewScopedpublic class Products implements Serializable {

// Properties ---------------------------------------------------------------------------------

@ManagedProperty("#{activeUser}") private ActiveUser activeUser;

// Getters/setters ----------------------------------------------------------------------------

public void setActiveUser(ActiveUser activeUser) { this.activeUser = activeUser; }

// ...

}

Note that a getter is not required in this particular case.

Back to top

Injecting request parameters in a view scoped beanYou can only inject a managed property of the same or a broader scope. So for example injecting request parameters as a managedproperty in a view scoped bean is (unfortunately) not going to work.

Following will not work:

package com.example.controller;

import java.io.Serializable;

import javax.faces.bean.ManagedBean;import javax.faces.bean.ManagedProperty;import javax.faces.bean.ViewScoped;

@ManagedBean@ViewScopedpublic class Bean implements Serializable {

// Properties ---------------------------------------------------------------------------------

@ManagedProperty("#{param.foo}") private String foo;

// Getters/setters ----------------------------------------------------------------------------

public void setFoo(String foo) { this.foo = foo;

Page 6: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

this.foo = foo; }

// ...

}

This will fail with the following error message:

Unable to create managed bean bean. The following problems were found: - The scope of the object referenced byexpression #{param.foo}, request, is shorter than the referring managed beans (bean) scope of view

To set request parameters in a view scoped bean, you would normally use <f:viewParam> tag as outlined in the chapter ProcessingGET request parameters. But it is possible to get them from the request parameter map during bean's (post)construction yourself.

// Properties ---------------------------------------------------------------------------------

private String foo;

// Init ---------------------------------------------------------------------------------------

@PostConstruct public void init() { FacesContext facesContext = FacesContext.getCurrentInstance(); this.foo = facesContext.getExternalContext().getRequestParameterMap().get(foo); }

Back to top

@ViewScoped fails in tag handlersWhen you bind an attribute of a tag handler by an EL value expression to a view scoped bean, then it will create a brand new viewscoped instance upon every request, even though it's a postback to the same view. This is a chicken-egg issue as stated in JSF issue1492 which is fixed in JSF 2.2 and for Mojarra 2.1 backported in version 2.1.18. Simply put, JSF needs to restore the partial view inorder to get the view state (and all view scoped beans) back. However, tag handlers runs during view build/restore time when JSF isabout to construct the component tree. So they will run first and not be aware about any beans available in the view scope. Whenrestoring the view is finished, the original view scoped beans are found and will be put back in the view scope. However, all EL valueexpressions of the tag handlers have already obtained the evaluated value of a completely different view scoped bean instancebeforehand!

Following is an overview of all tag handlers:

<c:choose>

<c:forEach>

<c:if>

<c:set>

<f:actionListener>

<f:convertXxx> like <f:convertNumber>

Page 7: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

<f:facet>

<f:validateXxx> like <f:validateLongRange>

<f:valueChangeListener>

<ui:decorate>

<ui:composition>

<ui:include>

any custom tag file

If you really need to bind a tag handler attribute by EL to a view scoped bean, such as

<ui:include src="#{viewScopedBean.includeFileName}.xhtml" />

Then you need to turn off the partial state saving by the following context parameter in web.xml to get it to work properly:

<context-param> <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name> <param-value>false</param-value> </context-param>

Globally disabling the partial state saving has however the disadvantage that the view state size will grow in size. So if you're usingserver side state saving method, then the server's memory usage will increase, or if you're using client side state saving method, thenthe network bandwidth usage will increase. Basically, you get the same view state information as it was in JSF 1.x. If possible, you canalso just disable the partial state saving on a per-view basis by the following context parameter in web.xml:

<context-param> <param-name>javax.faces.FULL_STATE_SAVING_VIEW_IDS</param-name> <param-value>/some.xhtml,/other.xhtml</param-value> </context-param>

It accepts a comma separated string of all view IDs for which the partial state saving should be disabled. If you do not want to disable itin any way, then you should really replace all EL usage in tag handlers by normal JSF components. Here's an overview of all taghandlers and the alternative approaches:

<c:choose>: use rendered attribute instead

<c:forEach>: use <ui:repeat> component instead

<c:if>: use rendered attribute instead

<c:set>: use <ui:param>, <f:viewParam>, @ManagedProperty or @PostConstruct instead

<f:actionListener>: use actionListener attribute instead

<f:convertXxx> like <f:convertNumber>: use converter attribute or <f:converter> instead

<f:facet>: sorry, no alternative, just do not use EL on any of its attributes

Page 8: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

<f:validateXxx> like <f:validateLongRange>: use validator attribute or <f:validator> instead

<f:valueChangeListener>: use valueChangeListener attribute instead

<ui:decorate>: sorry, no alternative, just do not use EL on any of its attributes

<ui:composition>: sorry, no alternative, just do not use EL on any of its attributes

<ui:include>: use a bunch of <ui:fragment rendered> components with each a static <ui:include>

any custom tag file: make it a fullworthy JSF UIComponent instead

Here is an overview of stackoverflow.com questions and answers related to this:

JSTL in JSF2 Facelets... makes sense?

@PostConstruct method is called even if the ManagedBean has already been instantiated (e.g. on AJAX-calls)

ViewScoped bean getting constructed on every request… part 99

Why does f:validateDoubleRange only work for @SessionScoped?

JSF ViewScope calls constructor on every ajax request?

@ViewScoped Managed bean loads many times during postback

Back to top

Implicit navigationOnes who have worked with JSF 1.x navigation cases probably know what a hell of maintenance pain they can cause. Although, afterall, in properly designed JSF web application their use should have been very minimal. POST form submits should navigate to thesame page as the form and any results should be conditionally rendered on the very same page. In other words, the action methodsshould return an empty string, or null, or void anyway. Page-to-page navigation should take place by pure GET links, not bycommand links. This all is much better for user experience and SEO.

However, now JSF2 comes with two new components <h:link> and <h:button> which represents a pure GET link and button whichboth support the outcome attribute representing the navigation case outcome, the new implicit navigation support is more thanwelcome. You just have to specify the view ID (basically, just the filename and the folder path, if any) and JSF will take care aboutprefixing and/or suffixing the proper context path and FacesServlet mapping on the generated link and button in the HTML.

For example, the following view

<h:link value="Home" outcome="home" /> <h:link value="FAQ" outcome="faq" /> <h:link value="Contact" outcome="contact" />

will generate the following HTML

<a href="/contextname/home.xhtml">Home</a> <a href="/contextname/faq.xhtml">FAQ</a> <a href="/contextname/contact.xhtml">Contact</a>

Page 9: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

Back to top

Implicit EL objectsJSF2 EL comes with a bunch of implicit EL objects which you can use in the view next to the managed beans. It are the following:

#{component}: the current UIComponent

#{facesContext}: the current FacesContext

#{view}: the current UIViewRoot

#{request}: the current HttpServletRequest

#{session}: the current HttpSession

#{application}: the ServletContext

#{flash}: the current Flash (which also implements map)

#{cc}: the current composite component

#{requestScope}: the current request attribute map

#{viewScope}: the current view attribute map

#{sessionScope}: the current session attribute map

#{applicationScope}: the application attribute map

#{initParam}: the current context parameter map

#{param}: the current request parameter map

#{paramValues}: the current request parameter values map

#{header}: the current request header map

#{headerValues}: the current request header values map

#{cookie}: the current request cookie map

#{resource}: converts a JSF resource identifier to a concrete resource URL. See chapter 5.6.2.5 of JSF specification

Particularly the #{component} one is interesting. It's like this in Java (and JavaScript) code. Below is an usage example:

<h:inputText value="#{bean.value}" styleClass="#{component.valid ? '' : 'error'}" />

The #{component} of a <h:inputText> component refers to an instance of UIInput class which in turn has an isValid() method.So when you submit the form and a validation error occurs on the particular component, then the #{component.valid} will evaluatefalse which will then set the error class on the input. This allows you to easily style invalid inputs!

.error { background: #fee;}

Page 10: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

The #{resource} is primarily intented to be used in CSS stylesheets to locate background images as a JSF resource. Below is anusage example, assuming that the image file is identified by the resource library "layout" and the resource name"images/foo.png":

.someClass { background-image: url("#{resource['layout:images/foo.png']}");}

Note that the CSS stylesheet itself should be included by <h:outputStylesheet>, otherwise EL in the CSS stylesheet won't beresolved.

Back to top

Implicit output textSince JSF 2.0 / Facelets, it's possible to inline EL in template text without the need to wrap it in a <h:outputText>. This makes thesource code better readable. Even more, Facelets will implicitly escape any HTML as well, like as in a real <h:outputText>.

<p>Welcome, #{activeUser.name}!</p>

Only whenever you'd like to disable escaping using escape="false", or would like to assign id, styleClass, onclick, etcprogrammatically, then you still need <h:outputText>.

Back to top

Normal (synchronous) POST formThis is how a Facelet file with a normal POST form look like without any JSF2 ajax fanciness. Such a form would work perfectly fine inJSF1. We'll use this form as a kickoff to add JSF2 ajax fanciness in the following few chapters.

<!DOCTYPE html><html lang="en" 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"> <h:head> <title>Page Title</title> </h:head> <h:body> <h:form id="form"> <h:panelGrid columns="3"> <h:outputLabel for="input1" value="Input 1" /> <h:inputText id="input1" value="#{bean.input1}" required="true" /> <h:message id="input1message" for="input1" />

<h:outputLabel for="input2" value="Input 2" /> <h:inputText id="input2" value="#{bean.input2}" required="true" /> <h:message id="input2message" for="input2" />

<h:panelGroup /> <h:commandButton value="Submit" action="#{bean.submit}" />

Page 11: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

<h:commandButton value="Submit" action="#{bean.submit}" /> <h:messages id="messages" globalOnly="true" layout="table" /> </h:panelGrid> </h:form> </h:body></html>

Some notes to the HTML/CSS purists:

Yes, a tab leless form with a shitload of CSS would semantically have been more correct, but that's beyond the scope of thistutorial, we teach JSF, not CSS.

Yes, a HTML5 doctype is perfectly fine. Long story short, read this: Is it possib le to use JSF/Facelets with HTML4/5?

Here's how the appropriate backing bean can look like:

package com.example.controller;

import javax.faces.application.FacesMessage;import javax.faces.bean.ManagedBean;import javax.faces.bean.RequestScoped;import javax.faces.context.FacesContext;

@ManagedBean@RequestScopedpublic class Bean {

// Properties ---------------------------------------------------------------------------------

private String input1; private String input2; // Actions ------------------------------------------------------------------------------------

public void submit() { String message = String.format("Submitted: input1=%s, input2=%s", input1, input2); FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(message)); }

// Getters/setters ----------------------------------------------------------------------------

public String getInput1() { return input1; }

public void setInput1(String input1) { this.input1 = input1; }

public String getInput2() { return input2; }

public void setInput2(String input2) { this.input2 = input2; }

}

Page 12: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

Back to top

Ajax (asynchronous) POST formTurning a normal form into an ajax form is a matter of adding <f:ajax> to the UICommand component.

<h:commandButton value="Submit" action="#{bean.submit}"> <f:ajax execute="@form" render="@form" /> </h:commandButton>

This requires that you're using <h:head> instead of <head>, otherwise the JSF-bundled Ajax helper JavaScript file won't be auto-included! When you run JSF with project stage set to "Development" by the following context parameter in web.xml,

<context-param> <param-name>javax.faces.PROJECT_STAGE</param-name> <param-value>Development</param-value> </context-param>

then you would be noticed about this mistake by the following development error message:

· One or more resources have the target of 'head', but no 'head' component has been defined within the view.

Coming back to the JSF2 <f:ajax> tag:

The <f:ajax>'s execute attribute defaults to @this (which is in this particular case the sole UICommand component itself). So inputvalues won't be submitted. You need to explicitly specify execute="@form" to submit the whole form. Or when you want to submitspecific input components only, such as the first one, then use execute="@this input1". Yes, it's space separated (PrimeFaces forexample also supports comma separation, but JSF2 thus not). Using @this is mandatory in order to let the button's action to executeanyway.

The <f:ajax>'s render attribute defaults to @none. You would like to render the entire form, so that validation messages will show up.You need to explicitly specify render="@form" then. Alternatively, maybe to save bandwidth, you can also specify to render only themessage components. In this case, use render="input1message input2message messages". This may however end up to becumbersome and hard-to-maintain.

The <f:ajax> has also an event attribute. The default value depends on the enclosing component. In case of UICommandcomponents this defaults to event="action" which is perfectly fine to submit a form. JSF will then take care that the right HTML DOMevent is been used to hook on an action, which is "click" in case of a standard command button and link.

Back to top

Ajax validationThis is a matter of adding <f:ajax> to the UIInput component with a render ID which points to the associated messagecomponent(s).

<h:outputLabel for="input1" value="Input 1" /> <h:inputText id="input1" value="#{bean.input1}" required="true">

Page 13: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

<h:inputText id="input1" value="#{bean.input1}" required="true"> <f:ajax event="blur" render="input1message" /> </h:inputText> <h:message id="input1message" for="input1" />

<h:outputLabel for="input2" value="Input 2" /> <h:inputText id="input2" value="#{bean.input2}" required="true"> <f:ajax event="blur" render="input2message" /> </h:inputText> <h:message id="input2message" for="input2" />

<h:panelGroup /> <h:commandButton value="Submit" action="#{bean.submit}"> <f:ajax execute="@form" render="input1message input2message messages" /> </h:commandButton> <h:messages id="messages" globalOnly="true" layout="table" />

The <f:ajax>'s event attribute defaults in UIInput components to event="valueChange". JSF will then take care that the rightHTML DOM event is been used to hook on a value change, which is "change" in case of text inputs and dropdowns and which is"click" in case of checkboxes and radiobuttons. However, in case of text inputs, when you tab along the required fields withoutentering a value, then the change event won't be fired. This may be affordable in some cases, but for the case that you would like tovalidate the text input immediately when the user leaves the field, then rather use event="blur".

Note that the <f:ajax>'s render attribute of the UICommand component in the above example has been changed to render themessage components only. You can also use render="@form" here. Both approaches are equally fine. It's a matter of taste andmaintainability.

The managed bean #{bean} can be placed in the request scope for such a form. But, with a big BUT, a request scoped managedbean will be recreated on every ajax request! You would like to use a view scoped managed bean instead. It'll live as long as you'refiring ajax requests from the same view on and the regular action methods returns all null or void. Once a managed bean actionmethod returns a valid navigation case outcome, even though it's to the same view, the view scoped managed bean will be garbagedand recreated.

package com.example.controller;

import java.io.Serializable;

import javax.faces.bean.ManagedBean;import javax.faces.bean.ViewScoped;

@ManagedBean@ViewScopedpublic class Bean implements Serializable {

// ...

}

Back to top

Ajax rendering of content outside formRender IDs are resolved relative to the parent UINamingContainer component. Examples of UINamingContainer components are<h:form>, <h:dataTable>, <ui:repeat>, etc. It are those components which prepends the client ID of their children with its ownclient ID.

Page 14: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

Following will not work:

<h:form id="form"> <h:commandButton value="Submit"> <f:ajax render="result" /> </h:commandButton> </h:form> <h:outputText id="result" value="#{bean.result}" />

Some JSF implementations/libraries would immediately show an error for this, either as a HTTP 500 error or some warning in theserver log. Mojarra for example would throw an exception with a message like this (the j_idt6 is in this particular case just theautogenerated ID of the command button):

<f:ajax> contains an unknown id 'result' - cannot locate it in the context of the component j_idt6

If you prefix render ID with ":" then it's resolved relative to the view root. It becomes the absolute render ID.

Following will work:

<h:form id="form"> <h:commandButton value="Submit"> <f:ajax render=":result" /> </h:commandButton> </h:form> <h:outputText id="result" value="#{bean.result}" />

The absolute render ID needs to be the full client ID prefixed with ":". So if the render target is by itself nested in anotherUINamingContainer component, then you need to give it a fixed ID and include its ID as well.

<h:form id="form"> <h:commandButton value="Submit"> <f:ajax render=":otherform:result" /> </h:commandButton> </h:form> <h:form id="otherform"> <h:outputText id="result" value="#{bean.result}" /> </h:form>

An easy way to check for the right render ID is to check the client ID of the JSF-generated HTML element. Open the page in awebbrowser, rightclick and choose View Source. That's the JSF-generated HTML output. You need to locate the HTML element whichhas been generated by the JSF component in question. In case of a <h:outputText id="result"> which is been enclosed in a<h:form id="otherform"> it'll look like the following:

<span id="otherform:result"></span>

You need to grab exactly that client ID and then prefix with ":" for the absolute render ID.

Page 15: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

Back to top

Ajax rendering of content which contains another formWhen you ajax render some content which in turn contains another form, then it won't work flawlessly because the other form wouldlose its view state. The view state is stored in a hidden input field with the name javax.faces.ViewState. The JSF JavaScript libraryis supposed to re-add the hidden field after ajax render.

Following will not work:

<h:panelGroup id="firstPanel"> <h:form id="firstForm"> <h:outputLabel for="input" value="First form input" /> <h:inputText id="input" value="#{bean1.input}" required="true" /> <h:commandButton value="Submit form" action="#{bean1.submit}"> <f:ajax execute="@form" render="@form :secondPanel :messages" /> </h:commandButton> <h:message for="input" /> </h:form> </h:panelGroup> <h:panelGroup id="secondPanel"> <h:form id="secondForm"> <h:outputLabel for="input" value="Second form input" /> <h:inputText id="input" value="#{bean2.input}" required="true" /> <h:commandButton value="Submit other form" action="#{bean2.submit}"> <f:ajax execute="@form" render="@form :firstPanel :messages" /> </h:commandButton> <h:message for="input" /> </h:form> </h:panelGroup> <h:messages id="messages" globalOnly="true" layout="table" />

Now, leave the fields empty and click the submit button of the first form. A validation error shows for the first input. This is fine. Now clickthe submit button of the second form with the fields still empty. You'd expect that a validation error shows for the second input. But itdoes not show up! Only the validation error of the first form disappears. When you would have entered the field, the managed beanaction method of the second form would not be invoked. You need to click the button twice to get it to work. Repeat then the same onthe first form and so on. You need to enter the field and click the button once again everytime to get the form to be submitted.

What is happening here is that the javax.faces.ViewState hidden input field is not added to the other form. This is an issue in theJSF JavaScript library and already acknowledged by the JSF spec guys and is currently been scheduled to be fixed in 2.3: JSF specissue 790. Both Mojarra and MyFaces exposes the same issue. To get it to work you would need to explicitly add the client ID of theother form in the <f:ajax> render.

<h:panelGroup id="firstPanel"> <h:form id="firstForm"> <h:outputLabel for="input" value="First form input" /> <h:inputText id="input" value="#{bean1.input}" required="true" /> <h:commandButton value="Submit form" action="#{bean1.submit}"> <f:ajax execute="@form" render="@form :secondPanel :secondForm :messages" /> </h:commandButton> <h:message for="input" /> </h:form> </h:panelGroup>

Page 16: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

</h:panelGroup> <h:panelGroup id="secondPanel"> <h:form id="secondForm"> <h:outputLabel for="input" value="Second form input" /> <h:inputText id="input" value="#{bean2.input}" required="true" /> <h:commandButton value="Submit other form" action="#{bean2.submit}"> <f:ajax execute="@form" render="@form :firstPanel :firstForm :messages" /> </h:commandButton> <h:message for="input" /> </h:form> </h:panelGroup> <h:messages id="messages" globalOnly="true" layout="table" />

No, this does not cause an overhead in the JSF ajax response. Since the component referenced by :secondForm is already a child ofthe component referenced by :secondPanel, this will just be skipped in the JSF ajax response. But the JSF JavaScript library will nowadd the mandatory javax.faces.ViewState hidden input field to the second form.

Back to top

Automatically fix missing JSF view state after ajax renderingAn alternative to explicitly specifying the forms in ajax render is to include this piece of JavaScript which should automatically detect anymissing javax.faces.ViewState hidden input fields and automatically append them:

jsf.ajax.addOnEvent(function(data) { if (data.status == "success") { var viewState = getViewState(data.responseXML);

for (var i = 0; i < document.forms.length; i++) { if (!hasViewState(document.forms[i])) { createViewState(document.forms[i], viewState); } } }});

function getViewState(responseXML) { var updates = responseXML.getElementsByTagName("update");

for (var i = 0; i < updates.length; i++) { if (updates[i].getAttribute("id") == "javax.faces.ViewState") { return updates[i].firstChild.nodeValue; } }

return null;}

function hasViewState(form) { for (var i = 0; i < form.elements.length; i++) { if (form.elements[i].name == "javax.faces.ViewState") { return true; } }

return false;}

Page 17: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

}

function createViewState(form, viewState) { var hidden; try { hidden = document.createElement("<input name='javax.faces.ViewState'>"); // IE6-8. } catch(e) { hidden = document.createElement("input"); hidden.setAttribute("name", "javax.faces.ViewState"); }

hidden.setAttribute("type", "hidden"); hidden.setAttribute("value", viewState); hidden.setAttribute("autocomplete", "off"); form.appendChild(hidden);}

Note that when you're using PrimeFaces and its own ajax components like <p:commandButton> and so on, then you don't need theabove workaround; they have already fixed this matter in their own core ajax engine.

Back to top

Ajax rendering of content which is by itself conditionally renderedAjax rendering takes place fully at the client side and expects the to-be-updated HTML element to be already in the JSF-generatedHTML output.

Following will not work when #{bean.renderResult} defaults to false:

<h:form id="form"> <h:commandButton value="Submit" action="#{bean.toggleRenderResult}"> <f:ajax render=":result" /> </h:commandButton> </h:form> <h:outputText id="result" value="#{bean.result}" rendered="#{bean.renderResult}" />

You need to ensure that the render ID points to a component which is already present in the JSF-generated HTML output.

Following will work:

<h:form id="form"> <h:commandButton value="Submit" action="#{bean.toggleRenderResult}"> <f:ajax render=":result" /> </h:commandButton> </h:form> <h:panelGroup id="result"> <h:outputText value="#{bean.result}" rendered="#{bean.renderResult}" /> </h:panelGroup>

Back to top

Passing POST action method arguments

Page 18: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

Since EL 2.2, which is maintained as part of Servlet 3.0 / JSP 2.2 (thus, Tomcat 7, Glassfish 3, JBoss AS 6, etc or newer), it is possibleto pass fullworthy objects as JSF action method arguments.

<h:form> <h:dataTable value="#{bean.users}" var="user"> <h:column>#{user.id}</h:column> <h:column>#{user.name}</h:column> <h:column>#{user.email}</h:column> <h:column><h:commandButton value="Edit" action="#{bean.edit(user)}" /></h:column> </h:dataTable> </h:form>

In combination with this bean method:

public void edit(User user) { this.user = user; this.edit = true; }

See also the article Benefits and pitfalls of @ViewScoped - Really simple CRUD, now without DataModel

Another interesting use case is the following:

<h:form> <f:ajax render=":include"> <h:commandLink value="Home" action="#{menu.setPage('home')}" /><br /> <h:commandLink value="FAQ" action="#{menu.setPage('faq')}" /><br /> <h:commandLink value="Contact" action="#{menu.setPage('contact')}" /><br /> </f:ajax> </h:form> <h:panelGroup id="include"> <ui:include src="#{menu.page}.xhtml" /> </h:panelGroup>

Note that you should specify the full setter method name in action attribute! Also note that this approach fails when the include pagecontains a form.

When you're still targeting an old Servlet 2.5 / JSP 2.1 container (e.g., Tomcat 6, Glassfish 2, JBoss AS 5, etc), then you can alwaysinstall JBoss EL to add the same enhancements for EL 2.1. Just grab and drop jboss-el-2.0.0.GA.jar in your webapp's /WEB-INF/libfolder and add the following (Mojarra-specific!) context parameter to your web.xml:

<context-param> <param-name>com.sun.faces.expressionFactory</param-name> <param-value>org.jboss.el.ExpressionFactoryImpl</param-value> </context-param>

Back to top

Processing GET request parameters

Page 19: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

JSF2 offers the new <f:viewParam> tag to set GET request parameters in a managed bean. Back in old JSF 1.x you could also setthem as a managed property in faces-config.xml, however that works on request scoped beans only and it does not allow for fine-grained conversion and validation. The new @ManagedProperty annotation does nothing different. The <f:viewParam> works onview scoped beans as well (and also on session and application scoped ones, but the benefit is questionable). It allows fordeclarative conversion and validation with <f:converter> and <f:validator> and even a <h:message> can be attached to it.

Let's first start with creating GET links with request parameters in a list:

<ul> <ui:repeat value="#{bean.users}" var="user"> <li> <h:link value="View details of #{user.name}" outcome="user"> <f:param name="id" value="#{user.id}" /> </h:link> </li> </ui:repeat> </ul>

The <h:link> will end up something like the following in the HTML:

<ul> <li><a href="/contextname/user.xhtml?id=123">View details of BalusC</a></li> <li><a href="/contextname/user.xhtml?id=456">View details of John Doe</a></li> <li><a href="/contextname/user.xhtml?id=789">View details of Nobody</a></li> </ul>

In the user.xhtml file, you can at its simplest use <f:viewParam> to set the id as a property of the managed bean and use<f:event type="preRenderView"> to trigger a managed bean method whenever all view parameters have been set:

<f:metadata> <f:viewParam name="id" value="#{bean.userId}" /> <f:event type="preRenderView" listener="#{bean.init}" /> </f:metadata> <h:head> <title>User Details</title> </h:head> <h:body> <h:messages /> <h:panelGrid columns="2" rendered="#{not empty bean.user}"> <h:outputText value="ID" /> <h:outputText value="#{bean.user.id}" />

<h:outputText value="Name" /> <h:outputText value="#{bean.user.name}" />

<h:outputText value="Email" /> <h:outputText value="#{bean.user.email}" /> </h:panelGrid> <h:link value="Back to all users" outcome="users" /> </h:body>

Page 20: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

Note: as per the upcoming JSF 2.2, the <f:event type="preRenderView"> could be replaced by a more self-documenting<f:viewAction>, see also this article of my fellow Arjan Tijms: What's new in JSF 2.2?

<f:viewAction action="#{bean.init}" />

Here's how the backing bean can look like:

package com.example.controller;

import java.io.Serializable;

import javax.faces.bean.ManagedBean;import javax.faces.bean.ViewScoped;

import com.example.business.UserService;import com.example.model.User;

@ManagedBean@ViewScopedpublic class Bean implements Serializable {

// Properties ---------------------------------------------------------------------------------

private Long userId; private User user;

// Services -----------------------------------------------------------------------------------

@EJB private UserService userService; // Actions ------------------------------------------------------------------------------------

public void init() { if (userId == null) { String message = "Bad request. Please use a link from within the system."; FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null)); return; }

user = userService.find(userId);

if (user == null) { String message = "Bad request. Unknown user."; FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null)); } }

// Getters/setters ----------------------------------------------------------------------------

public Long getUserId() { return userId; }

Page 21: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

public void setUserId(Long userId) { this.userId = userId; }

public User getUser() { return user; } }

Note that there's some unnecessary boilerplate code in the backing bean. Ultimately, you would like to end up with only the Userproperty. Check the next chapter.

Back to top

Converting and validating GET request parametersYou see, in the previous chapter there's some boilerplate in the init() which does the conversion (and essentially also validation).This can be improved by extracting the conversion from the backing bean into a fullworthy and reuseable Converter class as follows:

package com.example.converter;

import javax.ejb.EJB;import javax.faces.bean.ManagedBean;import javax.faces.bean.RequestScoped;import javax.faces.component.UIComponent;import javax.faces.context.FacesContext;import javax.faces.convert.Converter;import javax.faces.convert.ConverterException;

import com.example.business.UserService;import com.example.model.User;

@ManagedBean@RequestScoped // Can also be @ApplicationScoped if the Converter is entirely stateless.public class UserConverter implements Converter {

// Services -----------------------------------------------------------------------------------

@EJB private UserService userService;

// Actions ------------------------------------------------------------------------------------

@Override public String getAsString(FacesContext context, UIComponent component, Object value) { if (!(value instanceof User) || ((User) value).getId() == null) { return null; }

return String.valueOf(((User) value).getId()); }

@Override public Object getAsObject(FacesContext context, UIComponent component, String value) { if (value == null || !value.matches("\\d+")) { return null; }

Page 22: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

}

User user = userService.find(Long.valueOf(value));

if (user == null) { throw new ConverterException(new FacesMessage("Unknown user ID: " + value)); }

return user; }

}

Yes, it's a @ManagedBean instead of @FacesConverter! How awkward, but it's not possible to inject an @EJB inside a@FacesConverter in order to do the DB interaction job. The same problem manifests when you use the CDI @Inject to inject aproperty, you'd need to use @Named instead of @FacesConverter. The Java EE/JSF/CDI guys are working on that for the future JSF 2.2version, see also JSF spec issue 763. If you really need to have it to be a @FacesConverter (in order to utilize the forClass attribute,for example), then you can always manually grab the EJB from JNDI. See also the next chapter.

Now, you can specify the above converter in the converter attribute as follows and validate it as required as well. The appropriateerror messages can be specified by converterMessage and requiredMessage respectively. Please note that you need to specify theconverter in the view using converter="#{userConverter}" instead of converter="userConverter" because it's @ManagedBeaninstead of @FacesConverter.

<f:metadata> <f:viewParam name="id" value="#{bean.user}" converter="#{userConverter}" converterMessage="Bad request. Unknown user." required="true" requiredMessage="Bad request. Please use a link from within the system." /> </f:metadata>

Now we can make the backing bean more terse:

// Properties ---------------------------------------------------------------------------------

private User user;

// Getters/setters ----------------------------------------------------------------------------

public User getUser() { return user; } public void setUser(User user) { this.user = user; }

Back to top

Getting an EJB in @FacesConverter and @FacesValidatorThere's a way to get an EJB in a @FacesConverter and @FacesValidator. You only have to manually lookup it from JNDI. First createsome utility class which does the job. The below one assumes that EJBs are deployed in the WAR (as you would do in Java EE 6 Web

Page 23: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

Profile), for EARs you'd need to alter the EJB_CONTEXT to add the EJB module name:

package com.example.util;

import javax.naming.InitialContext;import javax.naming.NamingException;

/** * Utility class for EJBs. There's a {@link #lookup(Class)} method which allows you to lookup the * current instance of a given EJB class from the JNDI context. This utility class assumes that * EJBs are deployed in the WAR as you would do in Java EE 6 Web Profile. For EARs, you'd need to * alter the <code>EJB_CONTEXT</code> to add the EJB module name or to add another lookup() method. */public final class EJB {

// Constants ----------------------------------------------------------------------------------

private static final String EJB_CONTEXT;

static { try { EJB_CONTEXT = "java:global/" + new InitialContext().lookup("java:app/AppName") + "/"; } catch (NamingException e) { throw new ExceptionInInitializerError(e); } }

// Constructors -------------------------------------------------------------------------------

private EJB() { // Utility class, so hide default constructor. }

// Helpers ------------------------------------------------------------------------------------

/** * Lookup the current instance of the given EJB class from the JNDI context. If the given class * implements a local or remote interface, you must assign the return type to that interface to * prevent ClassCastException. No-interface EJB lookups can just be assigned to own type. E.g. * <li><code>IfaceEJB ifaceEJB = EJB.lookup(ConcreteEJB.class);</code> * <li><code>NoIfaceEJB noIfaceEJB = EJB.lookup(NoIfaceEJB.class);</code> * @param <T> The EJB type. * @param ejbClass The EJB class. * @return The instance of the given EJB class from the JNDI context. * @throws IllegalArgumentException If the given EJB class cannot be found in the JNDI context. */ @SuppressWarnings("unchecked") // Because of forced cast on (T). public static <T> T lookup(Class<T> ejbClass) { String jndiName = EJB_CONTEXT + ejbClass.getSimpleName();

try { // Do not use ejbClass.cast(). It will fail on local/remote interfaces. return (T) new InitialContext().lookup(jndiName); } catch (NamingException e) { throw new IllegalArgumentException( String.format("Cannot find EJB class %s in JNDI %s", ejbClass, jndiName), e); } }

Page 24: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

}

}

Note that this works in a Java EE 6 container only! In Java EE 5 and before, there's no way to obtain the application name from JNDI.You would need to hardcode it yourself or provide it by some configuration file (e.g. properties or XML file) or as VM argument.

Now you can turn the UserConverter into a fullworthy @FacesConverter:

package com.example.converter;

import javax.faces.component.UIComponent;import javax.faces.context.FacesContext;import javax.faces.convert.Converter;import javax.faces.convert.ConverterException;import javax.faces.convert.FacesConverter;

import com.example.business.UserService;import com.example.model.User;import com.example.util.EJB;

@FacesConverter(forClass=User.class)public class UserConverter implements Converter {

// Services -----------------------------------------------------------------------------------

private UserService userService = EJB.lookup(UserService.class);

// ...}

Thanks to the forClass attribute of the @FacesConverter, it will always be automatically invoked whenever a managed bean propertyof exactly the given type is to be converted. So, you can omit the converter attribute from the <f:viewParam>:

<f:metadata> <f:viewParam name="id" value="#{bean.user}" converterMessage="Bad request. Unknown user." required="true" requiredMessage="Bad request. Please use a link from within the system." /> </f:metadata>

Geplaatst door Bauke Scholtz op 7:22 PM

Labels: Ajax, Communication, EJB, JSF2

45 comments:

+18 Recommend this on Google

kiwifrog said...

Great article as usual. Crystal clear and informative.

Page 25: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

I was starting to miss your updates (no time to read StackOverflow).

Keep up the good work BalusC and thanks for sharing.

September 18, 2011 at 2:17 PM

Oleg Varaksin said...

Great post, even for experienced JSF developers (in order to brush up existing knowledge). Many thanks for your blog!

September 21, 2011 at 3:08 AM

Umoh said...

Dude, you're freaking awesome. I was literally Grinning and Shaking my head the whole Time. Its amazing how much I didn'tknow and How much stuff I was doing wrongly.Where do you get all this information from?

September 22, 2011 at 7:22 AM

Oleg Varaksin said...

One question yet. You have recommended to use static instead of dynamic one. With static includes we have a lot of blockswith rendered="true / false" and the component tree is very big. The big component tree is restored in the first JSF phase(not good). I prefer really dynamic includes. Do you know this post "Layouting and Dynamic Includes in Facelets"? -http://www.techbrainwave.com/?p=136&cpage=1 See last comments especially. What do you think about dynamic includeon postback?

September 22, 2011 at 11:30 AM

BalusC said...

@All: you're welcome :)

@Umoh: lot of practical experience and lot of reading/answering questions on Stackoverflow.

@Oleg: that article uses a session scoped bean. It will work without problems that way, but it get reflected on every browserwindow/tab and will thus result in unintuitive webapp behaviour (and bad user experience).

You really want a view scoped bean here, but it get reconstructed on every request! This is not immediately a problem for theinclude itself nor necessarily expensive, but this causes that any h:form which is placed inside the an include page otherthan the bean's default include page will not be found and not processed.

The workaround would be to put the h:form outside the ui:include and do not use the h:form inside an include page. But thisstill requires disabling the partial state saving.

If disabling the partial state saving is not an option due to memory issues, then you really need to use a bunch of staticincludes inside conditionally rendered UI components.

September 22, 2011 at 12:05 PM

Page 26: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

Oleg Varaksin said...

Thanks BalusC for your reply. I prefer session scoped bean for dynamic include. This is not a problem with browser tabs(ICEFaces has e.g. a special window scope). The problem is resource rendering. If you include new page fragments withnew components, the head section gets not updated automatically. That means, CSS / JS files declared with@ResourceDependency in included components are not available in the head. We discissed that issue in PrimeFacesforum and I found a solution which should be proved yet.

I have another question regardinsg DOCTYPE for HTML5. You told us about using that in facelets. I have used until nowXHTML 1.0 Transitional. What will happen if browser doesn't support HTML5? Is there a fallback? Is fallback Strict orTransitional mode? I have worries that JSF components of third libraries will not work smooth with DOCTYPE html in allbrowsers. PrimeFaces' showcase has e.g. XHTML 1.0 Transitional in facelets.

Thanks a lot in advance.

September 23, 2011 at 4:13 AM

BalusC said...

@Oleg: using HTML5 doctype works fine in all browsers expect of IE6 which will render in quirks mode (which is just alayout issue, the functionailty will remain just fine). IE6 usage is however greatly decreasing last years.

Failure/fallback in browsers only applies whenever you're using HTML5 specific elements such as <input type="range">,<canvas>, etc. This does not apply to HTML4 elements. Standard JSF implementations does not have any HTML5 specificelements, so it should work just fine in all browsers. The same applies to component libraries. Only PrimeFaces 3 forexample, has some HTML5 specific elements (e.g. file upload), but they gracefully degrades to HTML4 when the browserdoesn't support it.

September 23, 2011 at 8:40 AM

Oleg Varaksin said...

Hi,

Sure, I have understood. What I meant were pure widgets themself. I don't know, but some JS widgets used by PrimeFacesor wherever may expect HTML 4 Transitional to be able to use some CSS / HTML hacks. I'm sure if you would use Strictmode, some pages (layout etc.) could be broken. Therefore I asked about HTML5 DOCTYPE. But I think everything will beok. Have you ever tried PrimeFaces with DOCTYPE html?

Thanks.

September 23, 2011 at 11:18 AM

Lucas Theisen said...

You might want to add you solution to the circular managed bean reference using the setter of the parent to inject itself in thechild. That was useful and would fit nicely in your Injecting managed beans in each other section.

September 23, 2011 at 12:42 PM

Page 27: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

smithh032772 said...

Very good read, thanks BalusC! After reading some of your other posts/answers either here or on stackoverflow.com, Ichanged my JSF managed beans from SessionScoped to ViewScoped, and I just realized after reading this post that I canreference other managed beans via UIViewRoot.getViewMap() instead of getExternalContext().getSessionMap(). I'm going totry this and/or the managed property way of injecting managed bean in another managed bean (within the same scope, ofcourse).

Learning a lot from your BalusC. Thanks again!

November 23, 2011 at 5:50 PM

Patrick said...

Hi BalusC, "This release of Mojarra is not known to work in Apache Tomcat or Jetty." is declared as the known issue since2.1.1 till the latest 2.1.4. Wondering which version is workable for Tomcat (be it 6 or 7)?

November 24, 2011 at 7:41 AM

BalusC said...

@Patrick: only 2.1.0 doesn't work on Tomcat/Jetty. 2.1.1 and newer works on Tomcat. I tell from experience.

November 24, 2011 at 10:07 AM

Patrick said...

Haha, of course! I know you (your blog) since jsf 1. Just want to ensure it is the same mojarra that we are looking at, after allso many unfortune happen to jsf. Well, thanks for the prompt reply!

November 24, 2011 at 2:28 PM

ethereal said...

Thanks for the information BalusC, I was interested to see your comment about mojarra 2.1.x having fixed the issues withglassfish code that were breaking tomcat. Thanks to you and the information here and here, I was able to get mojarra 2.1.4running on tomcat 6.0.33, SWF 2.3.0, & Richfaces 4.0.0 :)

November 29, 2011 at 3:55 PM

undermanager said...

@BalusC - I've lost count of the times I've been researching a JSF question or issue and your name pops up with a solution- thank you for so many great articles and answers!

I see in your article here (and maybe articles elsewhere) that you focus on Faces managed beans and scopes (for example,@ManagedBean and javax.faces.bean.SessionScoped, and so on). There is, of course, also the CDI/Weld world (forexample, @Named and javax.enterprise.context.SessionScoped, and so on).

Do you have an opinion on when it makes sense to use one over the other? What factors are important in making thischoice?

Page 28: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

January 6, 2012 at 6:02 PM

Srikanth said...

Great Post!!- Thanks @BalusC

Its my first month on JSF 2.0 and your blog is such an awesome place for a person like me, which gives better solution forimplementing my use cases.

I have a question:- once redirecting to next page, does f:metadata or the managedbean gets loaded first ?

if f:metadata gets prior loaded then:

...

here f:event making a call to lstnr method in bean(ManagedBean), then Bean gets instantiated ?

And which way do you suggest f:metadata or @PostConstruct orFacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap()

Thanks in Adv.Once again Appreciate your Blog !!

January 29, 2012 at 6:54 AM

Rafael Ponte said...

Hi BalusC,

I believe you could use javax.faces.FULL_STATE_SAVING_VIEW_IDS context parameter rather thanjavax.faces.PARTIAL_STATE_SAVING=false to solving the @ViewScoped issues. Probably it's better than turningPARTIAL_STATE_SAVING off to entire application, right?

January 30, 2012 at 8:45 AM

Fernando Miño said...

MyFaces 2.1 targets Servlet 2.5, and is compatible with tomcat 6

February 8, 2012 at 5:34 PM

Caffé said...

Page 29: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

Whenever I need something about Java I get involved in a lot of non-useful posts, and I get more and more confused, until Ifind one of your posts. Thanks, BalusC! I have developed an application in Java and have no other resources away from theinternet. Thank you for your very honest and non-trivial posts.

February 13, 2012 at 8:27 PM

real said...

Thanks for sharing info. I've wasted two days for looking info about ViewState and dynamic facelets includes. Now it works.

February 20, 2012 at 10:45 AM

Unknown said...

@BalusC, excellent job. The section on "Ajax Rendering Of Content Which Is By Itself Conditionally Rendered" was exactlywhat I was trying to figure out.

My situation is that I have a textarea field that I want to be initially not rendered. I used the technique you described of puttingit inside a panel group. When the text box is checked, the textarea appears! However, now my problem is that when the formis submitted, the property of the managed bean which is bound to that textarea does not get set to whatever the user enteredin the textarea. What do I need to do to make this work?

March 15, 2012 at 6:26 PM

BalusC said...

@Unknown: put the bean in the view scope. This way the bean lives as long as you're interacting with the same view (byreturning null/void).

March 16, 2012 at 6:21 AM

tcprogrammer said...

@BalusC, I thought of using view scope, except the application calls for a number of different pages that the user must visitto fill in all the properties of the bean. For that reason I need it in session scope. I found another solution to hide/unhide thecomponent using java script which works for me in this case. But, I might have future cases where I really want to make anajax call. Is there a way to do this with a session bean?

March 16, 2012 at 1:30 PM

Carlos said...

I tried your solution to inject a CDI Bean using @Named in my Converter but it doesn't work. The converter cannot be found.Did I overlook something? I'm only using @Named in my Converter (without any other annotation)

March 27, 2012 at 6:24 AM

Kiddo said...

This comment has been removed by the author.

March 28, 2012 at 2:11 AM

Page 30: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

Kiddo said...

I'd like to create a list and detail pages for CRUD app with common layout and hence, I use facelet template.

In the list page, I have a data table with a link that passes the id to the detail page using f:param name="id" value="object.id".

In the detail page, I'll put the "f:viewParam" within "f:metadata" and load the data using preRenderView event.

But, because I use facelet template, everything outside "ui:composition" is thrown away and thus, the preRenderView eventwill not be called.

How to get around this?

Thx

March 28, 2012 at 2:17 AM

Jeancarlo Sott said...

Hi BalusC, greate article as always. I have a problem with data state. I have some menu items, they set the page (.xhtml) fora ui:include tag. The menu and the includes are working fine. The problem is when I change between menu items, the state(values) is not restored. Is this related to some of these STATE_SAVING props or is something to do with the right use of thecomponents, like the use of ui:include ? I'm using the last primefaces and myfaces and the bean is session scoped.

Thank youtJeancarlo.

March 29, 2012 at 4:36 PM

Traduce said...

How we can config web.xml when we are using the richfaces.Would you please show the example of richfaces in jsf 2.->I have used glassfish 3.1->Netbeans Id 6.9.1

i have tired to do with richfaces using in jsf2

May 7, 2012 at 8:07 AM

- said...

"Here's an overview of all tag handlers and the alternative approaches:...f:convertXxx like f:convertNumber: use converter attribute or f:converter instead...f:validateXxx like f:validateLongRange: use validator attribute or f:validator instead"

Maybe I'm missing something, but AFAI can see, f:converter and f:validator are tag handlers too?

Page 31: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

To get hold of a @ViewScoped bean inside my converter, I currently do FacesContext.getCurrentInstance().getApplication().evaluateExpressionGet(context, "#{" + beanName + "}", MyBean.class);

Is there a better way...?

July 20, 2012 at 6:23 AM

Lukas Meier said...

i'm just informing myself about jsf 2, so forgive me if I'm wrong. In your code details you refer to #{bean.initUser} and in yourclass you have the method Bean#init() - I guess you are addressing the very same method.

July 23, 2012 at 1:22 PM

Bauke Scholtz said...

@Lukas: sorry, that was a typo. I fixed it.

July 23, 2012 at 3:44 PM

fernandofranzini said...

Great post Bauke!!I have a doubt.I realized that in JSF 2, when filled with null fields are not rendered with rendering using the f: ajax or a4j: ajax. In fact nothinghappens, getting the same previous value. You know me explain why and how the fields are rendered with empty when theyare null?

August 7, 2012 at 11:05 AM

Jacob said...

BalusC

I have followed and practiced many tutorials which you have posted on your blog. It is very simple and easy to understand.

Could it be possible for you to write an article on EJB as I would like to know how to use EJB in applications.

Thanks and regards

Ponic

August 18, 2012 at 2:43 AM

Prashant Rathod said...

This comment has been removed by the author.

August 28, 2012 at 2:19 AM

amer sohail said...

Thanks for full of information.

Page 32: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

I have a question. I am using prime faces command button With ajax="true" to navigate from one page to another page. Onnavigated page i have to press button twice first time to make it work. After that all buttons work fine on first click. I know thereis a bug in jsf 2.1 that second page's state is lost with ajax navigation but u mentioned that it was handled in primefaces buti am still having that issue. I am using primefaces 3.4. Moreover i want to use commandbutton with ajax in order to avoid anyback button issue.

October 7, 2012 at 8:14 AM

Jonathan Bispo said...

Very good. It help me a lot. Thanks for the article.

November 8, 2012 at 5:48 PM

Kawu said...

What is the best scope of a CDI converter when the primary bean scope is view-scoped? I noticed I had annotated allconverters with @Named + @RequestScoped, but I fear @Named + ViewScoped would create much less overhead. Is thattrue?

December 13, 2012 at 8:35 AM

Jens Hartwig said...

Regarding "@ViewScoped fails in tag handlers": Shouldn't something like the following result in broken ViewScope?

January 3, 2013 at 6:03 PM

Jens Hartwig said...

sorry, the tag were purged...

https://gist.github.com/4447802

January 3, 2013 at 6:05 PM

Life has a twist said...

Hi,

I am facing the below problem:

on click of a button i am adding the details to a DB and returning the same. i return to the ssame page . i click on thehyperlink to retrieve the value i have just entered.

the value returned is null. Wat scope should be added. Pls help.

Thanks,

Page 33: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

Poo

April 9, 2013 at 7:15 AM

Chris Graham said...

Do you have/know a post that gives more information on this, specific to JSF, with rationale?:

> "POST form submits should navigate to the same page as the form and any results should be conditionally rendered onthe very same page. In other words, the action methods should return an empty string, or null, or void anyway. Page-to-pagenavigation should take place by pure GET links, not by command links. This all is much better for user experience and SEO."

Are you suggesting that a web app simply avoid having clicks that both perform an action and bring the user to a differentpage?This would rub our own usability-minded people the wrong way in terms of adding clicks to the workflow.

I have been thinking of posting-back pages as a prelude to any navigation, as good general practice.This has been useful to me in eg. remembering selections made on List Page X before drilling into Item Detail Page Y, laterto return to make more selections.

As well, it seems obvious for a Wizard, but perhaps that fits the definition of a special case.[

User experience issue-wise, I can understand the problem with the browser URL pointing to the "wrong" resource,destroying at least bookmarkability.And making any Refresh attempt a re-do of a form post.

But this sort of thing is normally handled by forcing a redirect, when considered important enough?Though I haven't tried this in JSF yet.

Are there additional issues, that I am not thinking of?

April 17, 2013 at 12:15 PM

Sameet Kumar Bhole said...

i need a help i need to send the activation mail to the user what he has specified the email address in create user page .and that mail should contain a link with temporary password which should generate randomly and that link which containmy specified page .Please help me out

April 26, 2013 at 7:01 AM

Koray said...

Hello,

Is this an Injection:

@EJBprivate UserService userService;

Page 34: Communication in JSF 2.0

pdfcrowd.comopen in browser PRO version Are you a developer? Try out the HTML to PDF API

Newer Post Older Post

Post a Comment

Home

Subscribe to: Post Comments (Atom)

Because it seems you do not initialize userService anywhere in the code?

May 6, 2013 at 7:56 AM

Koray said...

Hello,

Is this an Injection:

@EJBprivate UserService userService;

Because it seems you do not initialize userService anywhere in the code?

May 6, 2013 at 7:56 AM

Kodlapaylas said...

Greate article for JSF ! Thanks!!

June 13, 2013 at 3:54 PM

► Bean ► JSP ► Java Ajax ► JSF UI Components