Constructor injection in xwork action beans is not working correctly in Confluence 7.0

The ActionProxy is not initialized correctly when using constructor injection in Action Beans in combination with a method definition in the xwork module.
In the atlassian-plugin.xml if you define the action with a specific method

and use the constructor injection
ConfigureAction(SpaceManager spaceManager,…)
an Exception is thrown
java.lang.IllegalArgumentException: Method ‘input()’ is not defined in action ‘class com.siemens.confluence.pluginsettings.ConfigureAction’

Should constructor injection also be used for action beans or should they use the property injection?

2 Likes

I have the same issue. Did you manage to find a solution?
For now I’ve reverted back to using setter injection on the Action classes. But surely this is a bug?

The actions continue to work with setter injection. I removed the constructor and it works. The reason could be, that the action classes are no spring beans and therefore it is not necessary to change them.

You have a point. But if they are not indeed spring beans, I wonder how the setter injection works on them?

Its the xwork framework, which is responsible for this

I’ve been investigating this lately as well. I got deep down into the weeds of how XWork does its dependency injection.

My problem wasn’t trying to inject an Atlassian bean, but a bean from my own plugin’s code. The bean in question is marked with @ExportAsService, though it shouldn’t need to be.

What I found most odd was that the com.atlassian.confluence.core.ConfluenceAutowireInterceptor seemed to instantiate and inject my bean just fine. The problem came later in the process when com.opensymphony.xwork.ObjectFactory#buildBean(java.lang.String) tried to instantiate the object and couldn’t find a no-arg constructor (despite the fact that I had @Inject on the constructor and am using Atlassian Spring Scanner).

I think that the xwork stuff just isn’t quite ready for the brave new Spring Scanner world, but I’m not sure what the best solution is. Setter injection continues to work. I can also create the dependency bean by nabbing my plugin’s own org.springframework.beans.factory.BeanFactory and instantiating the dependent class that way.

This works fine for me, are you using Spring Scanner 2? I have my injecting classed marked with @Named annotation, not sure if this is even needed. But the constructor injection works just fine without any annotations for an AbstractUserProfileAction

1 Like

@StefanEnst - yeah, we’re using Spring Scanner 2. I’m extending the com.atlassian.confluence.spaces.actions.SpaceAdminAction. That has a somewhat involved inheritance chain that ultimately leads up to com.opensymphony.xwork.ActionSupport.

I’ve been testing in Confluence 6.10, since that’s the earliest version that Atlassian still support. Does this work in a later version of Confluence, perhaps? (UPDATE: same problem in Confluence 7.1 as well).

Also, just to verify… the @Named bean in question is your bean, right? Not an Atlassian-provided service?

EDIT:

To say more about the underlying exception, it gets thrown by com.opensymphony.xwork.config.entities.ActionConfig#getMethod, which swallows it to throw a NoSuchMethodException.

The full stack trace is rather long, but here’s an abbreviated version:

java.lang.InstantiationException: com.acme.action.ConfluenceSpaceAdminAction
	at java.lang.Class.newInstance(Class.java:427)
	at com.opensymphony.xwork.ObjectFactory.buildBean(ObjectFactory.java:97)
	at com.opensymphony.xwork.ObjectFactory.buildAction(ObjectFactory.java:77)
	at com.atlassian.confluence.plugin.ConfluencePluginObjectFactory.buildAction(ConfluencePluginObjectFactory.java:50)
	at com.opensymphony.xwork.config.entities.ActionConfig.getMethod(ActionConfig.java:112)
	at com.opensymphony.xwork.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:292)
	at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:170)

......................................................
......... lots of internals here .........
......................................................

	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1385)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NoSuchMethodException: com.acme.action.ConfluenceSpaceAdminAction.<init>()
	at java.lang.Class.getConstructor0(Class.java:3082)
	at java.lang.Class.newInstance(Class.java:412)
	... 375 more

By poking at the debugger, I can see that the problem is that my xwork action doesn’t have a no-arg constructor, but xwork seems to expect it to.

Hi @jcarter - to add to this, yesterday I had a similar problem (it did affect constructor injection in general however), I had copied the META-INF/spring/ directory in IntelliJ and for some reason it ended up as META-INF.spring at the destination with IntelliJ displaying it the same way. Only checking the classes folder led me on the right path. So things can really break in subtle ways and there is no good way to debug them with spring scanner 2

1 Like