Dependency Injection in Struts2 Accessing Session Scoped Beans

Let’s start from looking what is a Scope.Strategy by looking at the docs. It says

Pluggable scoping strategy. Enables users to provide custom
implementations of request, session, and wizard scopes. Implement and
pass to
Container.setScopeStrategy(com.opensymphony.xwork2.inject.Scope.Strategy)

Ok, assume I want to implement session scope. Then I need to know the place where I could implement it. The framework has it’s extension points where where you could plug your extensions or simply extend the default implementation and provide your own custom implementations. This is easy done via looking at the BeanSelectionProvider. Then analyzing the stacktraces I decided the best point would be to extend the DefaultActionProxyFactory. Extending it requires to extend the DefaultActionProxy also.

public class MyActionProxyFactory extends DefaultActionProxyFactory {

    public MyActionProxyFactory() {
        super();
    }

    @Override
    public ActionProxy createActionProxy(ActionInvocation inv, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) {

        MyActionProxy proxy = new MyActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
        container.inject(proxy);
        container.setScopeStrategy(new MyScopeStrategy());
        proxy.prepare();
        return proxy;
    }
}

public class MyActionProxy extends DefaultActionProxy {

    protected MyActionProxy(ActionInvocation inv, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) {
        super(inv, namespace, actionName, methodName, executeResult, cleanupContext);
    }

    @Override
    protected void prepare() {
        super.prepare();
    }
}

public class MyScopeStrategy implements Scope.Strategy {

    @Override
    public <T> T findInRequest(Class<T> type, String name, Callable<? extends T> factory) throws Exception {
        return null;
    }

    @Override
    public <T> T findInSession(Class<T> type, String name, Callable<? extends T> factory) throws Exception {

        ActionContext context = ActionContext.getContext();
        SessionMap<String, T> sessionMap = (SessionMap<String, T>) context.getSession();

        if (sessionMap == null) {
            sessionMap = new SessionMap<String, T>(ServletActionContext.getRequest());
            context.setSession((Map<String, Object>) sessionMap);
        }

        T obj = sessionMap.get(name);

        if (obj == null) {
            obj = factory.call();
            sessionMap.put(name, obj);
        }
        return obj;
    }

    @Override
    public <T> T findInWizard(Class<T> type, String name, Callable<? extends T> factory) throws Exception {
        return null;
    }
}

In the configuration file struts.xml you should set the property

<constant name="struts.actionProxyFactory" value="jspbean.struts.factory.MyActionProxyFactory"/>

That’s all you need to inject a bean Session with the session scope. Similar implementations could be done for other scopes. Notice, that other scopes like singlton (used by default), thread, and default seems don’t require such pluggable extension. And the last word is about @Scoped annotation. It’s not used if you provide the beans via xml configuration. But if you supply the ContainerBuilder with the bean in any other way it’s able to find annotation on it and set the corresponding scope.

Leave a Comment