Basic JSF and spring integration

The Following steps outline how to build a simple dynamic webproject that integrates JSF and spring web context.

Step1: Create jsf2.0 faceted project, select the mojorra library as mentioned in previous posting

Step2: Best not to get into all the hard work manually handling all those transitive dependencies . So download the maven eclipse integration plugin into your eclipse IDE

Step 3: Once eclipse restarts, right click on your simple web project, and use the convert>convert to mavenprojectto above project. This will create a basic pom.xml file in the root of your project.

Step 4: Add the essential spring dependencies into the pom like this. I have included JSF2, Spring 3 and JSR-330 (DI) for the @inject annotation, and tomcars dependencies.

projectxmlns="

modelVersion4.0.0</modelVersion

groupIdjsf-spring</groupId

artifactIdjsf-spring</artifactId

version0.0.1-SNAPSHOT</version

descriptionsample jsf integration with spring framework </description

build

sourceDirectorysrc</sourceDirectory

plugins

plugin

artifactIdmaven-compiler-plugin</artifactId

version3.1</version

configuration

source1.6</source

target1.6</target

</configuration

</plugin

</plugins

</build

dependencies

dependency

groupIdorg.springframework</groupId

artifactIdspring-core</artifactId

version3.2.4.RELEASE</version

</dependency

dependency

groupIdorg.springframework</groupId

artifactIdspring-web</artifactId

version3.2.4.RELEASE</version

</dependency

<!-- JSR-330 -->

dependency

groupIdjavax.inject</groupId

artifactIdjavax.inject</artifactId

version1</version

</dependency

<!-- JSF -->

dependency

groupIdcom.sun.faces</groupId

artifactIdjsf-api</artifactId

version2.2.0</version

</dependency

dependency

groupIdcom.sun.faces</groupId

artifactIdjsf-impl</artifactId

version2.2.0</version

</dependency

dependency

groupIdjavax.servlet</groupId

artifactIdjstl</artifactId

version1.2</version

</dependency

dependency

groupIdjavax.servlet</groupId

artifactIdjavax.servlet-api</artifactId

version3.0.1</version

</dependency

dependency

groupIdjavax.servlet.jsp</groupId

artifactIdjavax.servlet.jsp-api</artifactId

version2.2.1</version

</dependency

<!-- EL -->

dependency

groupIdorg.glassfish.web</groupId

artifactIdel-impl</artifactId

version2.2</version

</dependency

<!--Tomcat 6 needs this -->

dependency

groupIdcom.sun.el</groupId

artifactIdel-ri</artifactId

version1.0</version

</dependency

</dependencies

</project

Step 5: Edit the faces-config.xml file to add the spring jsf resolver

<?xmlversion="1.0"encoding="UTF-8"?>

faces-config

xmlns="

xmlns:xsi="

xsi:schemaLocation="

version="2.2"

application

el-resolver

org.springframework.web.jsf.el.SpringBeanFacesELResolver

</el-resolver

</application

</faces-config

Step6: Edit your web.xml to add the spring listeners, so that your web.xml looks something like this

<?xmlversion="1.0"encoding="UTF-8"?>

web-appxmlns:xsi="

display-namejsf-spring</display-name

<!-- Spring Context Configuration' s Path definition -->

context-param

param-namecontextConfigLocation</param-name

param-value

/WEB-INF/applicationContext.xml

</param-value

</context-param

<!-- Change to "Production" when you are ready to deploy -->

context-param

param-namejavax.faces.PROJECT_STAGE</param-name

param-valueDevelopment</param-value

</context-param

servlet

servlet-nameFaces Servlet</servlet-name

servlet-classjavax.faces.webapp.FacesServlet</servlet-class

load-on-startup1</load-on-startup

</servlet

servlet-mapping

servlet-nameFaces Servlet</servlet-name

url-pattern*.xhtml</url-pattern

</servlet-mapping

context-param

descriptionState saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description

param-namejavax.faces.STATE_SAVING_METHOD</param-name

param-valueclient</param-value

</context-param

context-param

param-namejavax.servlet.jsp.jstl.fmt.localizationContext</param-name

param-valueresources.application</param-value

</context-param

listener

listener-classcom.sun.faces.config.ConfigureListener</listener-class

</listener

<!-- Add Support for Spring -->

listener

listener-class

org.springframework.web.context.ContextLoaderListener

</listener-class

</listener

listener

listener-class

org.springframework.web.context.request.RequestContextListener

</listener-class

</listener

</web-app

Step 7: By default the maven dependencies are not automatically picked up in the WAR packajing. So ensure the project picks up the maven dependencies do the following

if you are running the project as dynamic web project on a server within eclipse, then you should open the project properties (right click > properties) and select "Deployment Assembly". There click "add", select "build path entries", and choose "maven dependencies". This will instruct WTP to send the maven dependencies to the server dir.

Leave the deployment assembly configlooking like this

Step 8: Add spring web context xml file mirroring the name as per the web.xml configuration you use. With spring you can have many metameta data file not just one.

applicationContext.xml in WEB-INF directory

beansxmlns="

xmlns:xsi="

xmlns:context="

xsi:schemaLocation="

<!-- look for annotation based components -->

context:component-scanbase-package="com.softwood"/>

beanid="sampleBo"class="com.softwood.sample.bo.impl.SampleBoImpl"</bean

</beans

In this example I shall be using annotations and java config in spring as well as traditional xml config.

The first example uses an bean expressed as meta data in the <bean> tag the traditional way. The context:component-scantag asks the spring runtime to parse the base package directory (you can do filters on this etc see the spring annotation sections in the user guide) looking for spring annotations on your classes.

Step 9 : First Example. This next step covers more than way to hook jsf into spring. First I create an interface for the Spring business object (Bo) like this

(a)– interface definition

package com.softwood.sample.bo;

publicinterfaceSampleBo {

public String getMessage();

}

(b)– bus object implementation

In the first example the bean is expressed in the applicationContext.xml and is parsed at load time. The first implementation is a plain POJO – see declaration in step 8 above.

packagecom.softwood.sample.bo.impl;

importcom.softwood.sample.bo.SampleBo;

//standard spring bean implementing logic

publicclassSampleBoImplimplementsSampleBo {

public String getMessage() {

}

}

(c)– declare JSF backing bean in faces-config.xml

<?xmlversion="1.0"encoding="UTF-8"?>

faces-config

xmlns="

xmlns:xsi="

xsi:schemaLocation="

version="2.2"

application

el-resolver

org.springframework.web.jsf.el.SpringBeanFacesELResolver

</el-resolver

</application

managed-bean

managed-bean-namesampleBean</managed-bean-name

managed-bean-classcom.softwood.sample.jsfbean.SampleBean</managed-bean-class

managed-bean-scopesession</managed-bean-scope

managed-property

property-namesampleBo</property-name

value#{sampleBo}</value

</managed-property

</managed-bean

</faces-config

(d)– declare Sample bean

packagecom.softwood.sample.jsfbean;

importcom.softwood.sample.bo.SampleBo;

//standard JSF backing bean but uses spring DI to get the business object

publicclassSampleBeanimplementsjava.io.Serializable {

//later inject in faces-config.xml

SampleBosampleBo;

publicvoidsetSampleBo(SampleBosampleBo) {

this.sampleBo = sampleBo;

}

publicSampleBogetSampleBo() {

returnthis.sampleBo;

}

public String printMsgFromSpring() {

returnsampleBo.getMessage();

}

}

(e)Add the facelet driver web page

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN"

"

htmlxmlns="

xmlns:h="

h:body

h1JSF 2.0 + Spring Example</h1

#{sampleBean.printMsgFromSpring()}

</h:body

</html

(f)Run up the application and goto the web page and you should a response like below

Your first working sample of JSF and spring DI injection into jsf bean. However this is not quite ideal as you have two runtime contexts to work in, and JSF backing one and spring one, which is less that ideal

The following other examples end up showing how this can be consolidated and drop the jsf backing beans and just the spring container for holding the backing state for JSF.

Step 10: Other examples showing different approaches

I tried a couple of other approaches to make sure each worked.

My example project has ended up looking something like this in the project explorer, with one Sample#BoImpl per approach so you can see each option /attempt readily

We have done the first example – mixed mode jsf and spring contexts working.

Example 2: jsf backing bean expressed as spring component using annotations. The sample2bean is defined as Spring @Component, and given session scope. It continues to use spring DI to get a reference to the same sampleBo bean as used in the step 9 above.

packagecom.softwood.sample.jsfbean;

importorg.springframework.beans.factory.annotation.Autowired;

importorg.springframework.context.annotation.Scope;

importorg.springframework.stereotype.Component;

importcom.softwood.sample.bo.SampleBo;

//declares jsf bean as spring component in the spring container

@Component ("sample2Bean")

@Scope("session")

public class Sample2Bean {

@Autowired //injects spring service using spring DI

SampleBo sample2Bo;

public void setSampleBo(SampleBosampleBo) {

this.sample2Bo = sampleBo;

}

publicSampleBogetSampleBo() {

return this.sample2Bo;

}

public String printMsgFromSpring() {

return sample2Bo.getMessage();

}

}

And business object declared a spring service now within the spring container

packagecom.softwood.sample.bo.impl;

importorg.springframework.stereotype.Service;

importcom.softwood.sample.bo.SampleBo;

//standard spring bean implementing logic

@Service ("sample2Bo")

public class Sample2BoImpl implements SampleBo {

public String getMessage() {

return "spring @annotation: JSF 2 + Spring Integration";

}

}

And xhtml – which uses the EL to lookup the backing bean from spring container

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN"

"

htmlxmlns="

xmlns:h="

h:body

h1JSF 2.0 + Spring Example</h1

#{sample2Bean.printMsgFromSpring()}

</h:body

</html

What this shows is that you can store the jsf bean as a component in the spring container

I did a variant of 2, sample2refService where the xhtml directly looks up a Bo declared as a spring @Service as well which works !

Example 3. Using standard JSR 330 annotations. This example just replaces the spring @component and @Autowired annotations with the JSR 330 standard DI equivalents

packagecom.softwood.sample.jsfbean;

importjavax.inject.Inject;

importjavax.inject.Named;

importorg.springframework.context.annotation.Scope;

importcom.softwood.sample.bo.SampleBo;

@Named ("sample3Bean")

@Scope("session") //need this, JSR-330 in Spring context is singleton by default

public class Sample3Bean implements java.io.Serializable {

@Inject

SampleBo sample3Bo;

public void setSampleBo(SampleBosampleBo) {

this.sample3Bo = sampleBo;

}

publicSampleBogetSampleBo() {

return this.sample3Bo;

}

public String printMsgFromSpring() {

return sample3Bo.getMessage();

}

}

And the Bo expressed using @Named

packagecom.softwood.sample.bo.impl;

importjavax.inject.Named;

importcom.softwood.sample.bo.SampleBo;

//standard spring bean implementing logic

@Named ("sample3Bo")

public class Sample3BoImpl implements SampleBo {

public String getMessage() {

return "javax @Named annotation: JSF 2 + Spring Integration";

}

}

Which shows the following in the browser

Example 4 : This example drops the jsf like backing bean approach and directly looks up the spring service business object. Here the business object is declared using JSR-330 @Named annotation

packagecom.softwood.sample.bo.impl;

importjavax.inject.Named;

importorg.springframework.context.annotation.Scope;

importcom.softwood.sample.bo.SampleBo;

//standard JSR-330 implementing logic

@Named ("sample4Bo")

@Scope("session") //need this, JSR-330 in Spring context is singleton by default

public class Sample4BoImpl implements SampleBo {

public String getMessage() {

return "direct reference spring Bo - javax @Named annotation: JSF 2 + Spring Integration";

}

}

With xhtml file doing EL lookup for the Bo directly

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN"

"

htmlxmlns="

xmlns:h="

h:body

h1JSF 2.0 + Spring Example</h1

#{sample4Bo.getMessage()}

</h:body

</html

Example 5 : looking up a spring controller

In this example we declare the Bo as spring controller

packagecom.softwood.sample.bo.impl;

importorg.springframework.stereotype.Controller;

importcom.softwood.sample.bo.SampleBo;

//standard spring bean implementing logic

@Controller ("sample5Controller")

public class Sample5BoImpl implements SampleBo {

public String getMessage() {

return "spring controller @annotation: JSF 2 + Spring Integration";

}

}

With xhtml like this

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN"

"

htmlxmlns="

xmlns:h="

h:body

h1JSF 2.0 + Spring Example</h1

#{sample5Controller.getMessage()}

</h:body

</html

Which renders this in the browser

This pattern is essentially the same pattern now that grails would use where the web page invokes a controller, which can itself be injected with a service using standard grails DI.