Activating CDI in JSF 2.3
When I upgraded my Java EE 7 sample to the newest Java EE 8, the first thing confused me is the CDI beans are not recoganized 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 applicatoin in Java EE 8.
-
Create a Java web application, this can be done easily by NetBeans IDE, or generated by Maven archetype, for exmaple.
$ mvn archetype:generate -DgroupId=com.example -DartifactId=demo -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
-
Add
javaee-api
in project dependencies.
<properties> <version.javaee-api>8.0</version.javaee-api> ...// other properties </properties> <dependencyManagement> <dependencies> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>${version.javaee-api}</version> <scope>provided</scope> </dependency> ...//other dependencies </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> </dependency> ...//other dependencies </dependencies>
-
Add a faces-config.xml into WEB-INF folder, it is optional in JSF 2.3.
<?xml version='1.0' encoding='UTF-8'?> <faces-config 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/web-facesconfig_2_3.xsd" version="2.3"> </faces-config>
-
Declare a beans.xml, CDI is enabled by default in Java EE 7, so it is optional.
<?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_2_0.xsd" bean-discovery-mode="all" version="2.0"> </beans>
-
Add web.xml. It is not required by JSF, but you can customize the application by some properties.
<?xml version="1.0" encoding="UTF-8"?> <web-app 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/web-app_4_0.xsd" version="4.0"> <context-param> <param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name> <param-value>0</param-value> </context-param> <context-param> <param-name>javax.faces.PROJECT_STAGE</param-name> <param-value>Development</param-value> </context-param> <context-param> <param-name>javax.faces.validator.ENABLE_VALIDATE_WHOLE_BEAN</param-name> <param-value>true</param-value> </context-param> <context-param> <param-name>javax.faces.ENABLE_WEBSOCKET_ENDPOINT</param-name> <param-value>true</param-value> </context-param> <!-- <context-param> <param-name>javax.faces.DISABLE_FACESSERVLET_TO_XHTML</param-name> <param-value>true</param-name> </context-param>--> </web-app>
ENABLE_VALIDATE_WHOLE_BEAN
is used to enable class level Bean validationENABLE_WEBSOCKET_ENDPOINT
is used to enable websocket supportDISABLE_FACESSERVLET_TO_XHTML
will disable JSF servelt mapping to *.xhtml. By default, JSF Servlet will serve *.xhtml.
-
Declare a
@FacesConfig
annotated class to activate CDI in JSF 2.3.
@FacesConfig( // Activates CDI build-in beans version = JSF_2_3 ) public class ConfigurationBean { }
FacesConfig
, you will know it is a standard CDIQualifier
.
@Qualifier @Target(TYPE) @Retention(RUNTIME) public @interface FacesConfig { public static enum Version { /** * <p class="changed_added_2_3">This value indicates CDI should be used * for EL resolution as well as enabling JSF CDI injection, as specified * in Section 5.6.3 "CDI for EL Resolution" and Section 5.9 "CDI Integration".</p> */ JSF_2_3 } /** * <p class="changed_added_2_3">The value of this attribute indicates that * features corresponding to this version must be enabled for this application.</p> * @return the spec version for which the features must be enabled. */ @Nonbinding Version version() default Version.JSF_2_3; }
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.
@Named
@RequestScoped
public class HelloBean {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public void sayHi() {
this.message = this.message+ " received at " + LocalDateTime.now();
}
@Override
public int hashCode() {
int hash = 7;
hash = 13 * hash + Objects.hashCode(this.message);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final HelloBean other = (HelloBean) obj;
if (!Objects.equals(this.message, other.message)) {
return false;
}
return true;
}
}
<!DOCTYPE html>
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:jsf="http://xmlns.jcp.org/jsf">
<h:head/>
<h:messages />
<h:body>
<p>
Hello JSF 2.3 with CDI activation
</p>
<form jsf:id="form">
<p>
<strong>Welcome to JSF 2.3 world: </strong>
<div>#{helloBean.message}</div>
</p>
<p>
<strong>Message: </strong>
<div><input type="text" jsf:id="message" jsf:value="#{helloBean.message}"></input></div>
</p>
<p>
<input type="submit" value="Say Hi to JSF" jsf:action="#{helloBean.sayHi()}" />
</p>
</form>
</h:body>
</html>
评论
Angularjs Online Training