Hello everyone. If you are using JSF with spring beans, than you may notice that there are no alternative for JSF view scope in Spring. But to combine Spring with JSF you have to use Spring context with its beans.

If you will try to add JSF annotations to Spring beans - you will fail. It will not work because native JSF  beans actually have another context environment than spring. Thus all JSF annotations and configuration from faces-config.xml can not be applied to Spring beans.

Someone could think that configuring JSF with spring resolver should fix all issues.

<!-- somewhere in faces-config.xml -->
<application>
    <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>

Unfortunately that this trick allowing only access Spring beans from JSF pages by ID. It just skip JSF scope with all it features and just proxy everything to Spring context.

So what could we do about this?

Solution 1 - forget about Spring beans in JSF pages

Actually it not so bad idea if we will skip mentioning that JSF is actually a dying technology.

Solution 2 - let’s code a little

The main idea to solve this issue is to use original JSF context view map for storing Spring beans. The simplest solution to do this is implement your own Spring Scope to interact with FacesContext.getCurrentInstance().getViewRoot().getViewMap().

import java.util.Map;
import javax.faces.context.FacesContext;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;

public class SpringViewJsfScope implements Scope {

    @Override
    public Object get(String name, ObjectFactory objectFactory) {
        Map<string object=""> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();

        if (viewMap.containsKey(name)) {
            return viewMap.get(name);
        } else {
            Object object = objectFactory.getObject();
            viewMap.put(name, object);
            return object;
        }
    }

    @Override
    public Object remove(String name) {
        return FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove(name);
    }

    @Override
    public String getConversationId() {
        return null;
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
        //Not supported
    }

    @Override
    public Object resolveContextualObject(String key) {
        return null;
    }
}

Next you have to add this scope into your applicationContext.xml.

<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
        <map>
            <entry key="view">
                <bean class="your.package.SpringViewJsfScope"/>
            </entry>
        </map>
    </property>
</bean>

Look good but beware! Above example covers only basic functionality and may not be useful on heavily loaded applications.

Solution 3 - use my module

I’ve take raw solution somewhere in the net, done some patches and publish it as maven artifact. It is available here JSF view scope for Spring context.

Based on the same idea as in solution 2, but with a little bit more tweaking. This plugin will allow you to integrate Spring view scope for JSF very easy. All you need to to is: 1. add artifact to your maven or gradle project 2. put next line into your Spring config

<import resource="classpath:/com/github/javaplugs/jsf/jsfSpringScope.xml"/>

After that you will be able to use:

  • scope="view" in xml config
  • @SpringScopeView annotation
  • @SpringScopeRequest @SpringScopeSession annotations for other scopes