
Injecting JSF artifacts
The JSF specification predates CDI. As such, many JSF artifacts, such as FacesContext and ExternalContext, had to be obtained via static entry methods; this resulted in hard-to-read boilerplate code. JSF 2.3 introduces the ability to inject JSF artifacts via CDI's @Inject annotation, as seen in the following example:
package net.ensode.javaee8book.jsfarbitrarymess; import java.io.Serializable; import javax.faces.application.FacesMessage; import javax.faces.context.FacesContext; import javax.faces.view.ViewScoped; import javax.inject.Inject; import javax.inject.Named; @Named @ViewScoped public class ArbitraryMessageController implements Serializable { @Inject
FacesContext facesContext; public void saveData() { FacesMessage facesMessage = new
FacesMessage(FacesMessage.SEVERITY_INFO, "Data saved successfully", "All Data successfully
saved."); facesContext.addMessage(null, facesMessage); } }
In this example, we need an instance of FacesContext so that we can send an arbitrary message to an <h:messages> component; as of JSF 2.3, we can simply annotate our instance of FacesContext with CDI's @Inject annotation.
Chapter 5, Contexts and Dependency Injection, covers CDI in detail.
In order for us to be able to successfully inject a JSF artifact into our CDI named beans, we need to add a CDI beans.xml deployment descriptor to the WEB-INF directory of our WAR file, making sure to set the bean-discovery-mode attribute of its <beans> tag to all:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" bean-discovery-mode="all"> </beans>
Additionally, we need to have a class in our WAR file annotated with the @FacesConfig annotation (we use this annotation to specify we are using JSF 2.3):
package net.ensode.javaee8book.jsfarbitrarymess.config; import javax.faces.annotation.FacesConfig; @FacesConfig(version = FacesConfig.Version.JSF_2_3) public class ConfigurationBean { }
As can be seen in the preceding example, the class containing the @FacesConfig annotation doesn't have to have any code. We specify that we are using JSF 2.3 by passing FacesConfig.Version.JSF_2_3 as the value of the annotation's version attribute.
In addition to illustrating how to inject the JSF artifact, this example illustrates a JSF feature we haven't seen before—the ability to send arbitrary messages to an <h:messages> component via the addMessage() method of FacesContext. Next, we show the markup corresponding to the preceding CDI named bean:
<?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:h="http://xmlns.jcp.org/jsf/html" xmlns:f="http://xmlns.jcp.org/jsf/core"> <h:head> <title>JSF Arbitrary Messages Demo</title> </h:head> <h:body> <h:outputStylesheet library="css" name="styles.css"/> <h:messages id="messages" /> <h:form> <h:panelGrid columns="2" columnClasses="rightAlign,leftAlign"> <!-- Irrelevant markup omitted for brevity --> <h:commandButton
actionListener="#
{arbitraryMessageController.saveData()}"
value="Save">
<f:ajax render="messages"/>
</h:commandButton> </h:panelGrid> </h:form> </h:body> </html>
When the user clicks on the button generated by the <h:commandButton> component, the saveData() method of our CDI named bean is invoked, which in turn creates an instance of FacesMessage and passes it to the addMessage() method of FacesContext, resulting in the message being shown in the browser.
In case it isn't obvious, this simple example doesn't actually save any data; all we are illustrating here is how to pass arbitrary messages to the JSF <h:messages> component.
The following screenshot assumes the user has already pressed the Save button. The message at the top is the result of our invocation to the addMessage() method of FacesContext: