Activating CDI in JSF 2.3
When I upgraed my Java EE 7 sample to the newest Java EE 8, the first thing confused me is the CDI beans are not recognized in Facelects template in a JSF 2.3 based web applicaiton, which is working in the development version, but in the final release version, they are always resolved as null. I filed an issue on Mojarra and discussed it with the developers from communities and the JSF experts.
According to the content of README, In a JSF 2.3 application, to activate CDI support, declaring a 2.3 versioned faces-config.xml and adding javax.faces.ENABLE_CDI_RESOLVER_CHAIN in web.xml is not enough, you have to declare @FacesConfig annotated class to enable CDI.
Here is the steps I created a workable JSF 2.3 application in Java EE 8.
    1.
    Create a Java web application, this can be done easily by NetBeans IDE, or generated by Maven archetype, for example.
    1
    $ mvn archetype:generate -DgroupId=com.example
    2
    -DartifactId=demo
    3
    -DarchetypeArtifactId=maven-archetype-webapp
    4
    -DinteractiveMode=false
    Copied!
    2.
    Add javaee-api in project dependencies.
    1
    <properties>
    2
    <version.javaee-api>8.0</version.javaee-api>
    3
    ...// other properties
    4
    </properties>
    5
    <dependencyManagement>
    6
    <dependencies>
    7
    <dependency>
    8
    <groupId>javax</groupId>
    9
    <artifactId>javaee-api</artifactId>
    10
    <version>${version.javaee-api}</version>
    11
    <scope>provided</scope>
    12
    </dependency>
    13
    ...//other dependencies
    14
    </dependencies>
    15
    </dependencyManagement>
    16
    <dependencies>
    17
    <dependency>
    18
    <groupId>javax</groupId>
    19
    <artifactId>javaee-api</artifactId>
    20
    </dependency>
    21
    ...//other dependencies
    22
    </dependencies>
    Copied!
    3.
    Add a faces-config.xml into WEB-INF folder, it is optional in JSF 2.3. ​
    1
    <?xml version='1.0' encoding='UTF-8'?>
    2
    <faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    3
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd"
    5
    version="2.3">
    6
    </faces-config>
    Copied!
    4.
    Declare a beans.xml, CDI is enabled by default in Java EE 7, so it is optional.
    1
    <?xml version="1.0" encoding="UTF-8"?>
    2
    <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    3
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
    5
    bean-discovery-mode="all"
    6
    version="2.0">
    7
    </beans>
    Copied!
    5.
    Add web.xml. It is not required by JSF, but you can customize the application by some properties.
    1
    <?xml version="1.0" encoding="UTF-8"?>
    2
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    3
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
    5
    version="4.0">
    6
    <context-param>
    7
    <param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
    8
    <param-value>0</param-value>
    9
    </context-param>
    10
    11
    <context-param>
    12
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    13
    <param-value>Development</param-value>
    14
    </context-param>
    15
    16
    <context-param>
    17
    <param-name>javax.faces.validator.ENABLE_VALIDATE_WHOLE_BEAN</param-name>
    18
    <param-value>true</param-value>
    19
    </context-param>
    20
    21
    <context-param>
    22
    <param-name>javax.faces.ENABLE_CDI_RESOLVER_CHAIN</param-name>
    23
    <param-value>true</param-value>
    24
    </context-param>
    25
    26
    <context-param>
    27
    <param-name>javax.faces.ENABLE_WEBSOCKET_ENDPOINT</param-name>
    28
    <param-value>true</param-value>
    29
    </context-param>
    30
    31
    <!-- <context-param>
    32
    <param-name>javax.faces.DISABLE_FACESSERVLET_TO_XHTML</param-name>
    33
    <param-value>true</param-name>
    34
    </context-param>-->
    35
    </web-app>
    Copied!
    JSF 2.3 provides some options to activate the new features added in 2.3.
      ENABLE_VALIDATE_WHOLE_BEAN is used to enable class level Bean validation
      ENABLE_WEBSOCKET_ENDPOINT is used to enable web socket support
      ENABLE_CDI_RESOLVER_CHAIN is originally designed for enabling CDI, but it seems it is replaced by @FacesConfig
      DISABLE_FACESSERVLET_TO_XHTML will disable JSF servlet mapping to *.xhtml. By default, JSF Servlet will serve \.xhtml*.
    6.
    Declare a @FacesConfig annotated class to activate CDI in JSF 2.3.
    1
    @FacesConfig(
    2
    // Activates CDI build-in beans
    3
    version = JSF_2_3
    4
    )
    5
    public class ConfigurationBean {
    6
    7
    }
    Copied!
    Open the source code of FacesConfig, you will know it is a standard CDI Qualifier.
    1
    @Qualifier
    2
    @Target(TYPE)
    3
    @Retention(RUNTIME)
    4
    public @interface FacesConfig {
    5
    6
    public static enum Version {
    7
    8
    /**
    9
    * <p class="changed_added_2_3">This value indicates CDI should be used
    10
    * for EL resolution as well as enabling JSF CDI injection, as specified
    11
    * in Section 5.6.3 "CDI for EL Resolution" and Section 5.9 "CDI Integration".</p>
    12
    */
    13
    JSF_2_3
    14
    15
    }
    16
    17
    /**
    18
    * <p class="changed_added_2_3">The value of this attribute indicates that
    19
    * features corresponding to this version must be enabled for this application.</p>
    20
    * @return the spec version for which the features must be enabled.
    21
    */
    22
    @Nonbinding Version version() default Version.JSF_2_3;
    23
    24
    }
    Copied!
Done.
Another issue about JSF 2.3 still confused me and other developers, as the codes shown above, we use all bean-discovery-mode in the beans.xml. If we switch to annotated here, we have to add @FacesConfig to every CDI backing beans, it is unreasonable.
Create a simple sample to verify if it works.
Firstly create a simple backing bean to say hello to JSF.
1
@Named
2
@RequestScoped
3
public class HelloBean {
4
5
private String message;
6
7
public String getMessage() {
8
return message;
9
}
10
11
public void setMessage(String message) {
12
this.message = message;
13
}
14
15
public void sayHi() {
16
this.message = this.message+ " received at " + LocalDateTime.now();
17
}
18
19
@Override
20
public int hashCode() {
21
int hash = 7;
22
hash = 13 * hash + Objects.hashCode(this.message);
23
return hash;
24
}
25
26
@Override
27
public boolean equals(Object obj) {
28
if (this == obj) {
29
return true;
30
}
31
if (obj == null) {
32
return false;
33
}
34
if (getClass() != obj.getClass()) {
35
return false;
36
}
37
final HelloBean other = (HelloBean) obj;
38
if (!Objects.equals(this.message, other.message)) {
39
return false;
40
}
41
return true;
42
}
43
44
}
Copied!
And template will accept user input and show the message.
1
<!DOCTYPE html>
2
<html lang="en"
3
xmlns="http://www.w3.org/1999/xhtml"
4
xmlns:h="http://xmlns.jcp.org/jsf/html"
5
xmlns:jsf="http://xmlns.jcp.org/jsf">
6
<h:head/>
7
8
<h:messages />
9
10
<h:body>
11
<p>
12
Hello JSF 2.3 with CDI activation
13
</p>
14
15
<form jsf:id="form">
16
<p>
17
<strong>Welcome to JSF 2.3 world: </strong>
18
<div>#{helloBean.message}</div>
19
</p>
20
<p>
21
<strong>Message: </strong>
22
<div><input type="text" jsf:id="message" jsf:value="#{helloBean.message}"></input></div>
23
</p>
24
<p>
25
<input type="submit" value="Say Hi to JSF" jsf:action="#{helloBean.sayHi()}" />
26
</p>
27
</form>
28
29
</h:body>
30
31
</html>
Copied!
Grab the source codes from my GitHub account.
Last modified 7mo ago
Copy link