History | Log In     View a printable version of the current page.  
Issue Details (XML | Word | Printable)

Key: XW-174
Type: Bug Bug
Status: Closed Closed
Resolution: Fixed
Priority: Major Major
Assignee: Jason Carreira
Reporter: Jim Cook
Votes: 1
Watchers: 2
Operations

If you were logged in you would be able to see more operations.
XWork

ObjectFactory requires same action to return same classname

Created: 13/Apr/04 12:32 PM   Updated: 14/Nov/04 11:58 AM
Component/s: None
Affects Version/s: 1.0.1
Fix Version/s: 1.0.4

File Attachments: 1. Text File ActionConfig.patch (2 kb)
2. Text File DefaultActionInvocation.patch (0.7 kb)
3. Text File patch.txt (73 kb)
4. Java Source File SpringObjectFactoryListener.java (1 kb)
5. Zip Archive xwork_patch.zip (38 kb)

Issue Links:
Related
This issue relates to:
XW-168 Spring/Xwork Action configuration Major Closed
 


 Description  « Hide
-- from mailing list --
I'm trying to debug a problem when WebWork 2 invokes an Action method on an Action that has been proxied using CGLIB. I'm loading the Action from Spring, and I've attached an AOP interceptor to my Action.

The ObjectFactory support in WebWork was causing me some grief. I think my problem is in this method:

DefaultActionInvocation.invokeAction(Action, ActionConfig)

At the time this method in called, by action has been generated from the SpringObjectFactory (but this could be *any* ObjectFactory implementation).
Since my Action is proxied by CGLIB, its value during debug looks something like this:

action: com.opensymphony.xwork.Action =
 
{us.oh.state.dot.jpp.web.action.SignonAction$$EnhancerByCGLIB$$bb4d4da@11528
}

The next thing that happens is that actionConfig.getMethod() is called to obtain a java.lang.reflect.Method object. The main problem I see is that the
getMethod() method in ActionConfig asks the ObjectFactory to create another instance of the Action. At best, this is unnessesary since the Action can be passed into this method call from the DefaultActionInvocation. Under normal circumstances it wouldn't be so bad since the method it pulls is cached in the ActionConfig.

At worst, in my case, the second instantiation of the Action produces a class that is not addressable to the original Action request. Basically, it seems that CGLIB proxies of the same target object are not able to be cast to each other's proxied targets. This means the Method that is returned has a different Action than the Action it will be invoked upon.

I know that probably sounds confusing as hell. I'm not sure how to make it clearer. Here is the error message I get when calling method.invoke(action, new Object[0]);

212719 [http8080-Processor25] ERROR
com.opensymphony.webwork.dispatcher.ServletDispatcher - Could not execute action
java.lang.IllegalArgumentException: object is not an instance of declaring class
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39
)
        at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl
.java:25)
        at java.lang.reflect.Method.invoke(Method.java:324)
        at
com.opensymphony.xwork.DefaultActionInvocation.invokeAction(DefaultActionInv
ocation.java:304)
        

I resolved the issue in my local code base by having the
ActionConfig.getMethod() call take Action as a parameter. It is only called from DefaultActionInvocation.invokeAction(), so this is no problem.

Since ActionConfig caches the method call between requests, I needed to defeat the caching of methods when the Actions are different classes. I did this by hanging on to the Action in ActionConfig between calls to getMethod(Action). If the action is not an instance of the prior stored action, I eject the method. I can attach some patches if this seems like a reasonable approach.

Not sure how this affects the ActionConfig. All the unit tests pass anyway, and it solves the mismatch in the invokeAction method.


 All   Comments   Change History      Sort Order:
Jim Cook - [13/Apr/04 12:53 PM ]
Attached patch for XWork CVS HEAD as of 13 Apr 2004. Patch local to <xwork>/src. Includes patches submitted in XW-168. The changes in XW-168 also require some modifications to WebWork.

Jim Cook - [13/Apr/04 01:05 PM ]
I'd like to create a patch on WebWork but that Jalopy crap has caused some files on my machine to be styled, and others on the CVS server to be styled. It's a mess now and I can't create a decent patch. The WebWork changes were pretty straight-forward.

I did include a ContextListener to bootstrap the SpringObjectFactory configuration in WebWork, so I have attached that file.

BTW, using Spring as an object factory rocks.

Jim Cook - [13/Apr/04 03:58 PM ]
Raw files that have been changed as a result of the patch.

Jim Cook - [13/Apr/04 04:00 PM ]
Added a ContextListener that bootstraps the SpringObjectFactory.

Jason Carreira - [14/Apr/04 10:33 PM ]
From what Chris Nokelberg said, this sounds like it's actually a Spring bug... Should we close it and let them fix it? I'm not big on making XWork more complicated to work around optional libraries bugs...

Jim Cook - [15/Apr/04 02:53 PM ]
I guess as the designers, you guys will have to make that decision. I think Chris was indicating that this isn't expected behavior from CGLIB's caching mechanism. I'm not so sure it is a Spring mistake.

I guess the true "architecture" question, is whether XWork should choose to implement the invoker in a manner that can allow a third-party library to produce an unchecked exception. The recent (welcome) addition of an external ObjectFactory requires that the ObjectFactory play by certain rules at this point. If not fixed, they should at least be documented.

Regardless of whether this bug is addressed is the work that Simon Stewart did to extend the ObjectFactory to Spring. That is also part of this patch.

I hope that both things can be resolved.

Jason Carreira - [19/Apr/04 08:59 AM ]
This isn't compatible with the latest stuff from Simon Stewart, because it no longer has the Class instance... Take a look at CVS head in XWork and see what you think (and if it's still broken).

I think it would be good to check these things anyway, even if this is a Spring bug, because Spring could change the implementation returned for a name under us and we'd end up with errors again.

Let me know what you find.

Patrick Lightbody - [21/Jul/04 12:55 PM ]
Moving this to 1.1 for now.

Scott Turnquet - [11/Aug/04 12:16 AM ]
In Spring Framework v1.0.2 each proxied bean is returned as a new class enhanced by cglib. So when using SpringObjectFactory.buildAction with spring 1.0.2 each proxied action is a different class. This causes problems when using reflection as the method returned from ActionConfig.getMethod() belongs to a different class than the object it is being invoked on. This problem has been fixed in Spring 1.1RC1. Spring 1.1RC1 now uses a factory to avoid recreating an enhancer configuration when generating a proxy for a previously proxied bean. The net affect for xwork's SpringObjectFactory is that the action returned from buildAction will now be the same as the action passed to DefaultActionInvocation.invokeAction(Action, ActionConfig). No class conflict. No reflection problems.

See Spring's jira issue: SPR-175

Matthew Payne - [25/Aug/04 10:03 AM ]
Has there been any progress on this? If I "auto-proxy" an
action from spring it works for a little while.

Later invocations cause a stack trace like below.
Its tough to predict when the are going to stop working. Many times it takes and idle period and they I try 3 minutes later.

Is Xwork caching the actions?

i.e. they are not being freshly retrieved from the external object factory?

--->

java.lang.IllegalArgumentException: object is not an instance of declaring class
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
java.lang.reflect.Method.invoke(Unknown Source)
com.opensymphony.xwork.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:302)
com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:170)
com.opensymphony.xwork.interceptor.AroundInterceptor.intercept(AroundInterceptor.java:35)
com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:165)
com.opensymphony.xwork.interceptor.AroundInterceptor.intercept(AroundInterceptor.java:35)
com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:165)
com.opensymphony.xwork.interceptor.AroundInterceptor.intercept(AroundInterceptor.java:35)
com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:165)
com.opensymphony.xwork.interceptor.AroundInterceptor.intercept(AroundInterceptor.java:35)
com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:165)
com.opensymphony.xwork.interceptor.AroundInterceptor.intercept(AroundInterceptor.java:35)
com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:165)
com.opensymphony.xwork.DefaultActionProxy.execute(DefaultActionProxy.java:115)
com.opensymphony.webwork.dispatcher.ServletDispatcher.serviceAction(ServletDispatcher.java:278)
com.opensymphony.webwork.dispatcher.ServletDispatcher.service(ServletDispatcher.java:248)
javax.servlet.http.HttpServlet.service(HttpServlet.java:810)
com.opensymphony.webwork.lifecycle.RequestLifecycleFilter.doFilter(RequestLifecycleFilter.java:69)
com.opensymphony.module.sitemesh.filter.PageFilter.parsePage(PageFilter.java:142)
com.opensymphony.module.sitemesh.filter.PageFilter.doFilter(PageFilter.java:58)
org.springframework.orm.hibernate.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:161)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:73)

Matthew Payne - [25/Aug/04 10:07 AM ]
Note I am using spring RC1.1. It has not fixed the product(perhaps made it take longer for the problem to occur).

Matt

Matthew Payne - [01/Sep/04 02:19 PM ]
patch for ActionConfig (1 or 2 files )

Matthew Payne - [01/Sep/04 02:20 PM ]
(2 or 2) files