2010-07-08

JSF 2.0 + Maven

In this article I will show you how to create a basic JSF 2.0 application with Maven, for JBoss 6.0.0-RC3.


JSF 2.0


JSF is a framework for building web applications using reusable components, and it’s focused on UI components. This allows you to write less HTML, which is a good thing.

What’s new compared to JSF 1.x?


In this article


I will present basic configuration of a JSF 2.0 project with Maven. Nothing fancy.


Maven pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>me.m1key.jsf</groupId>
  <artifactId>sample</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <build>
      <finalName>sample</finalName>
      <plugins>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-compiler-plugin</artifactId>
              <version>2.0.2</version>
              <configuration>
                  <source>1.6</source>
                  <target>1.6</target>
              </configuration>
          </plugin>
      </plugins>
  </build>
  <dependencies>
      <dependency>
          <groupId>javax.faces</groupId>
          <artifactId>jsf-api</artifactId>
          <version>2.0.2-FCS</version>
          <scope>provided</scope>
      </dependency>
      <dependency>
          <groupId>javax.faces</groupId>
          <artifactId>jsf-impl</artifactId>
          <version>2.0.2-FCS</version>
          <scope>provided</scope>
      </dependency>
  </dependencies>
  <repositories>
      <repository>
          <id>JBoss.org</id>
          <name>JBoss Repository</name>
          <url>http://repository.jboss.com/maven2</url>
      </repository>
  </repositories>
</project>

Why those versions of JSF? Well, that’s exactly what JBoss 6.0.0-RC3 uses.


faces-config.xml


No faces-config.xml - we don’t need it!


Managed bean


package me.m1key.jsf;

import javax.faces.bean.ManagedBean;

@ManagedBean
public class UserBean {
  private String name;

  public String getName() {
      return name;
  }

  public void setName(String name) {
      this.name = name;
  }

  public String send() {
      return "hello";
  }
}

Because we are using the @ManagedBean annotation, we don’t need to declare the bean anywhere else. You can override this configuration with faces-config.xml, if you need to.

The send() method returns a String “hello". Automatically, .xhtml is going to be appended to it and a view hello.xhtml will be resolved. No need to declare the rule. Convention over configuration.

The default scope of this bean is request. You can modify the default scope.

// ...
// import javax.faces.bean.RequestScoped;
import javax.faces.bean.SessionScoped;

@ManagedBean
// @RequestScoped
@SessionScoped
public class UserBean {
// ...

  • @RequestScoped
  • @SessionScoped
  • @ApplicationScoped - one bean for all
  • @ViewScoped - the same bean is used as long as the user stays on the page (this is for AJAX)
  • @CustomScoped - stores the bean in a map; developer controls it
  • @NoneScoped - not in scope. Normally referenced by other beans that are in scope

Because it’s a managed bean, you can use JEE goodies (such as @EJB etc.) if you run your application on a JEE server .

Read more about managed beans validation and dependency injection using annotations.

I think that the JSF way of doing dependency injection is somewhat cumbersome. If you’re on JEE 6, you may want to use the new CDI mechanism. Jacek Laskowski wrote an article on using CDI with Java SEE (so without a JEE6 server). The article is in Polish, but the source code isn’t.


web.xml


<!DOCTYPE web-app PUBLIC
    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
  <display-name>Web Application</display-name>

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

  <servlet>
      <servlet-name>Faces Servlet</servlet-name>
      <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
      <servlet-name>Faces Servlet</servlet-name>
      <url-pattern>*.xhtml</url-pattern>
  </servlet-mapping>
</web-app>

Note the PROJECT_STAGE property. It’s new to JSF 2.0. You can read more about PROJECT_STAGE on Ryan Lubke’s blog.


The views


The view with a form:
<!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://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets">

  <h:head>
      <title>Index</title>
  </h:head>
  
  <h:body>
      <h:form>
          <h:inputText value="#{userBean.name}" />
          <h:commandButton value="Send" action="#{userBean.send}" />
      </h:form>
  </h:body>

</html>

The result view:
<!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://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets">

  <h:head>
      <title>Hello</title>
  </h:head>
  
  <h:body>
      <h1>Hello #{userBean.name}</h1>
  </h:body>

</html>


Summary


We created a simple JSF 2.0 application that uses a single managed bean and has 2 views. On that I will build another example, perhaps something using CDI.

Download source code for this article

4 comments:

  1. hi,

    out of curiosity I tried to rewrite pom.xml to Gradle (version 0.9-preview-3). This is the final build.gradle file:

    apply plugin: 'war'

    repositories {
    mavenRepo urls: 'http://repository.jboss.com/maven2'
    }

    dependencies {
    providedCompile 'javax.faces:jsf-api:2.0.2-FCS', 'javax.faces:jsf-impl:2.0.2-FCS'
    }

    The resulting WAR file is identical with the one generated by Maven (with one exception - no "maven" subfolder in META-INF).

    --
    Cheers,
    Tomek Kaczanowski

    ReplyDelete
  2. Tomek, thanks a lot!

    I still haven't looked into Gradle yet but I must (have you heard that Hibernate is switching to Gradle from Maven?).

    The Gradle file looks more concise. Is Java 1.6 the default one?

    ReplyDelete
  3. Hi Michał,

    lol at Hibernate - it was me who posted this info on dzone :)

    As for Java 1.6 - not sure about that but I think so.

    --
    Cheers,
    Tomek

    ReplyDelete
  4. Okay, I see. :)

    Have you gone Gradle too?

    ReplyDelete