I'm currently using Struts to develop an app, and the hello world page worked just fine until I made it extend ActionSupport
to get access to i18n features. Upon doing this, the action started always returning input
as the result string. This is obviously unexpected as there is no validation done at the moment. After debugging, I noticed that Spring decided to inject a field error map, so validation always sees something, causing the unexpected return value.
] 1
Here is the stack trace:
Daemon Thread [http-0.0.0.0-8080-2] (Suspended (breakpoint at line 79 in ActionSupport))
Index(ActionSupport).setFieldErrors(Map<String,List<String>>) line: 79
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: not available
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: not available
Method.invoke(Object, Object...) line: not available
BeanWrapperImpl.setPropertyValue(BeanWrapperImpl$PropertyTokenHolder, PropertyValue) line: 1134
BeanWrapperImpl.setPropertyValue(PropertyValue) line: 903
BeanWrapperImpl(AbstractPropertyAccessor).setPropertyValues(PropertyValues, boolean, boolean) line: 75
BeanWrapperImpl(AbstractPropertyAccessor).setPropertyValues(PropertyValues) line: 57
DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).applyPropertyValues(String, BeanDefinition, BeanWrapper, PropertyValues) line: 1450
DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).populateBean(String, RootBeanDefinition, BeanWrapper) line: 1158
DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).autowireBeanProperties(Object, int, boolean) line: 376
StrutsSpringObjectFactory(SpringObjectFactory).autoWireBean(Object, AutowireCapableBeanFactory) line: 218
StrutsSpringObjectFactory(SpringObjectFactory).buildBean(Class, Map<String,Object>) line: 198
StrutsSpringObjectFactory(SpringObjectFactory).buildBean(String, Map<String,Object>, boolean) line: 164
StrutsSpringObjectFactory(ObjectFactory).buildBean(String, Map<String,Object>) line: 178
DefaultActionFactory.buildAction(String, String, ActionConfig, Map<String,Object>) line: 22
StrutsSpringObjectFactory(ObjectFactory).buildAction(String, String, ActionConfig, Map<String,Object>) line: 148
DefaultActionInvocation.createAction(Map<String,Object>) line: 295
DefaultActionInvocation.init(ActionProxy) line: 395
StrutsActionProxy(DefaultActionProxy).prepare() line: 194
StrutsActionProxy.prepare() line: 63
StrutsActionProxyFactory.createActionProxy(ActionInvocation, String, String, String, boolean, boolean) line: 37
StrutsActionProxyFactory(DefaultActionProxyFactory).createActionProxy(String, String, String, Map<String,Object>, boolean, boolean) line: 58
Dispatcher.serviceAction(HttpServletRequest, HttpServletResponse, ActionMapping) line: 554
ExecuteOperations.executeAction(HttpServletRequest, HttpServletResponse, ActionMapping) line: 81
StrutsPrepareAndExecuteFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 99
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206
OpenSessionInViewFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 232
OpenSessionInViewFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 106
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206
ReplyHeaderFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 96
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206
StandardWrapperValve.invoke(Request, Response) line: 230
StandardContextValve.invoke(Request, Response) line: 175
SecurityAssociationValve.invoke(Request, Response) line: 182
JaccContextValve.invoke(Request, Response) line: 84
StandardHostValve.invoke(Request, Response) line: 127
ErrorReportValve.invoke(Request, Response) line: 102
CachedConnectionValve.invoke(Request, Response) line: 157
StandardEngineValve.invoke(Request, Response) line: 109
CoyoteAdapter.service(Request, Response) line: 262
Http11Processor.process(Socket) line: 844
Http11Protocol$Http11ConnectionHandler.process(Socket) line: 583
JIoEndpoint$Worker.run() line: 446
Thread.run() line: not available
This is basically all that the class contains:
public class Index extends ActionSupport implements UserAware
{
private User user;
@Override
public String execute()
{
System.out.println("this doesn't print out");
return "SUCCESS";
}
@Override
public void setUser(User user)
{
this.user = user;
}
public User getUser()
{
return user;
}
}
I'm only using the @Autowired
annotated property injection, so I'd like to disable the method injection to fix this issue. That is of course if that is the problem. I could have misinterpreted the symptoms.
Struts and Spring does not go well together by default, You need to add struts2-spring-plugin-xyzjar in your WEB-INF/lib from your struts lib directory. and configure it properly in web.xml, refer this http://www.tutorialspoint.com/struts_2/struts_spring.htm
This happens due to ActionSupport
implements all interfaces required for validation, like Validatable
and ValidationAware
.
ValidationAware
classes can acceptAction
(class level) or field level error messages. Action level messages are kept in aCollection
. Field level error messages are kept in aMap
fromString
field name to aList
of field error messages.
The last one is more specific to injection of errors but it's not a Spring job (Spring uses its object factory to build the action and inject its dependencies), it's a Struts job to support the action with field errors and action errors, and it's well done with the validation
interceptor.
This interceptor runs the action through the standard validation framework, which in turn checks the action against any validation rules (found in files such as
ActionClass-validation.xml
) and adds field-level and action-level error messages (provided that the action implementscom.opensymphony.xwork2.ValidationAware
).
The validation
interceptor is included in the defaultStack
which is used by default in any action. If the action doesn't need the validation capabilities you can remove this interceptor from the stack by creating a new stack, or overriding the action config. If the validation is provided to other methods, then you can exclude some methods from the interceptor or apply a @SkipValidation
annotation. That would disable the validation from the method of the action.
I was able to fix this by changing the autowire type to none
in the struts.xml
file. I initially set it to type
because I thought that @Autowire
injection wouldn't work otherwise. I guess I was wrong since those injections still work.
<constant name="struts.objectFactory.spring.autoWire" value="type" />
to
<constant name="struts.objectFactory.spring.autoWire" value="none" />
Thanks to all participants for helping.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.