跳至主要内容

Activating CDI in JSF 2.3

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 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.
  1. 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 
    
  2. 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>
  3. 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>
  4. 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>
  5. 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_CDI_RESOLVER_CHAIN</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>
    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 websocket support
    • ENABLE_CDI_RESOLVER_CHAIN is orginally designed for enabling CDI, but it seems it is replaced by @FacesConfig
    • DISABLE_FACESSERVLET_TO_XHTML will disable JSF servelt mapping to *.xhtml. By default, JSF Servlet will serve *.xhtml.
  6. 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 {
    
    }
    Open the source code of FacesConfig, you will know it is a standard CDI Qualifier.
    @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;
    
    }
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.
@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;
    }

}
And template will accept user input and show the message.
<!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>
Grab the source codes from my github account.

评论

此博客中的热门博文

Build a Reactive application with Angular 5 and Spring Boot 2.0

I have created a post to describe Reactive programming supports in Spring 5 and its subprojects, all codes of this article are updated the latest Spring 5 RELEASE, check spring-reactive-sample under my Github account.
In this post, I will create a simple blog system, including:
A user can sign in and sign out.An authenticated user can create a post.An authenticated user can update a post.Only the user who has ADMIN role can delete a post.All users(including anonymous users) can view post list and post details.An authenticated user can add his comments to a certain post. The backend will be built with the latest Spring 5 reactive stack, including:
Spring Boot 2.0, at the moment the latest version is 2.0.0.M7Spring Data MongoDB supports reactive operations for MongoDBSpring Session adds reactive support for WebSessionSpring Security 5 aligns with Spring 5 reactive stack The frontend is an Angular based SPA and it will be generated by Angular CLI.
The source code is hosted on Github, …

JSF 2.3:Websocket support

Websocket support One of the most attractive features is JSF 2.3 added native websocket support, it means you can write real-time applications with JSF and no need extra effort.
To enable websocket support, you have to add javax.faces.ENABLE_WEBSOCKET_ENDPOINT in web.xml.
<context-param> <param-name>javax.faces.ENABLE_WEBSOCKET_ENDPOINT</param-name> <param-value>true</param-value> </context-param> Hello Websocket Let's start with a simple example.
@ViewScoped@Named("helloBean") publicclassHelloBeanimplementsSerializable { privatestaticfinalLoggerLOG=Logger.getLogger(HelloBean.class.getName()); @Inject@PushPushContext helloChannel; String message; publicvoidsendMessage() { LOG.log(Level.INFO, "send push message"); this.sendPushMessage("hello"); } privatevoidsendPushMessage(Objectmessage) { helloChannel.send(""+ message +" at &…