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.
Struts 2 bean configuration default scope
The default scope is singleton
, but there's a scope with name default
which is different. May be this question let you better understand scopes in Struts2. The framework support scopes like singleton
, default
, and thread
other scopes you should implement manually.
Look at the source code where the scopes are defined.
To clarify the scope named default
means a one instance per injection. You can find this in comments to Scope.DEFAULT.
Is there a way to bind OGNL with Struts2 UI tags
You could try having the name be the string session.order.amount
and make your action implement SessionAware, and expose the session. Currently you're setting the name to the value of session.order.amount
.
I don't know if it would work, and you might need to use array/collection notation, but off the top of my head I don't know why it wouldn't work.
That said, I feel like direct view-layer writes into web app internals is a Bad Idea.
Scopes in Struts 2 and standards for them
Struts 2 is running a container, it has scopes for beans. More about bean scopes is in this question. All other scopes are servlet scopes. Struts uses indirect access to these scopes using it's own structures. For example a set
tag uses these scopes:
The scopes available are as follows :
application - the value will be set in application scope according to servlet spec. using the name as its key
session - the value will be set in session scope according to servlet spec. using the name as key
request - the value will be set in request scope according to servlet spec. using the name as key
page - the value will be set in page scope according to servlet sepc. using the name as key
action - the value will be set in the request scope and Struts' action context using the name as key
NOTE:
If no scope is specified, it will default to action scope.
@Inject not working in Jersey REST webservices in Struts 2
From the official CDI Plugin documentation:
Use the right
@Inject
Struts 2 and it's core component XWork use it's own internal
dependency injection container. Interestingly, you could name it
JSR-330's grandma, since it is an early pre-release version of Google
Guice once developed by Crazybob Lee - the same Bob Lee that, together
with SpringSource's Rod Johnson, lead the JSR-330 specification.That said, you will find the
@Inject
annotation both as
com.opensymphony.xwork2.inject.Inject
andjavax.inject.Inject
. Don't
mix up those two -javax.inject.Inject
is the one you want to use with
your Struts 2 CDI plugin and CDI integration in general! While you
could use Struts' internal annotation as well, the effect may be
strange to undefined - so check your imports!
Then instead of com.opensymphony.xwork2.inject.Inject
use the correct one: javax.inject.Inject
Scope attribute migration from Struts1 to Struts2
From the Struts 1 DTD in the Action Element definition:
scope The context ("request" or "session") that is used to
access our ActionForm bean, if any. Optional if "name" is
specified, else not valid. [session]
In Struts 2, there are no Action Form beans, and Actions themselves default to request context. @meskobalazs is correct above, this can be overridden with the scope interceptor if you need session-scoped actions in Struts 2.
Related Topics
Java Division by Zero Doesnt Throw an Arithmeticexception - Why
Load Resource from Anywhere in Classpath
Java, "Variable Name" Cannot Be Resolved to a Variable
How to Change the Shape of a Jtabbedpane Tab
What Does an Exclamation Mark Mean in Java
Why Converting from Float to Double Changes the Value
Variable's Scope in a Switch Case
How to Convert Binary String Value to Decimal
Java.Lang.Classcastexception Using Lambda Expressions in Spark Job on Remote Server
How to Get the Desktop Path in Java
In Java, When Does an Object Become Unreachable
How to Flatten 2D Array to 1D Array
Maven Compilation Error: (Use -Source 7 or Higher to Enable Diamond Operator)
Getting a Illegalblocksizeexception: Data Must Not Be Longer Than 256 Bytes When Using Rsa