Struts 2 action method intercepting using Spring AOP - spring

I'm trying to intercept the Struts2 Action class's methods to print the method start and method end indication statement using Spring AOP.
The fact is , my Struts2 actions instance are also Spring beans (Struts2 and Spring integration done as per the url: http://www.mkyong.com/struts2/struts-2-spring-integration-example/). AOP configurations is as below:
<bean id="testAdviceBean" class="com.tcs.oss.plugins.SimpleAdvice">
</bean>
<aop:config>
<aop:aspect ref="testAdviceBean" order="200">
<aop:pointcut id="testPoint2"
expression="execution(java.lang.String com.test..DeviceAction.*(..))"
/>
<aop:around pointcut-ref="testPoint2" method="loggingAdvice" />
</aop:aspect>
</aop:config>
In the advice method loggingAdvice , I'm trying to print the method START and method END statement using the ProceedingJoinPoint API.The advice method is not called at all ... instead it's ending up with the error below after going through the struts default interceptor chain ...
But I'm getting the below ERROR TRACE:
09:26:49,093 TRACE
[org.springframework.beans.factory.support.DefaultListableBeanFactory]
(http-01h3463916-172.20.211.235-8543-5) Ignoring constructor [public
org.apache.struts2.dispatcher.ServletDispatcherResult(java.lang.String)]
of bean 'org.apache.struts2.dispatcher.ServletDispatcherResult':
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name
'org.apache.struts2.dispatcher.ServletDispatcherResult': Unsatisfied
dependency expressed through constructor argument with index 0 of type
[java.lang.String]: : No matching bean of type [java.lang.String]
found for dependency: expected at least 1 bean which qualifies as
autowire candidate for this dependency. Dependency annotations: {};
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
matching bean of type [java.lang.String] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for
this dependency. Dependency annotations: {}
09:26:49,095 TRACE
[org.springframework.beans.factory.support.DefaultListableBeanFactory]
(http-01h3463916-172.20.211.235-8543-5) Not autowiring property
'urlHelper' of bean
'org.apache.struts2.dispatcher.ServletDispatcherResult' by name: no
matching bean found
09:26:49,100 DEBUG
[org.apache.struts2.dispatcher.ServletDispatcherResult]
(http-01h3463916-172.20.211.235-8543-5) Forwarding to location
/General/error.jsp
If I just remove the above AOP configurations, It's just working fine. What I'm doing wrong ?

The advice method is not called because Action class was extending from ActionSupport class which in turn has a interface implementations... So , in this case, A JDK proxy was created for the Action class -- This type of proxy doesn't have any method specific(non-inheritance) to the Action class.
Adding proxy-target-class="true" attribute, in the AOP configuration, made the Spring to generate CGLib(need to add CGLib in the Classpath) based proxy.. which now has the non-inheritance methods too, of the Action class.

After a bunch of digging, I think I found the issue (if you're using Spring to help with AOP, even if you're not you're probably going to need a different ObjectFactory), long and short of it is that you need to make sure that the struts ObjectFactory is setup properly:
<constant name="struts.objectFactory" value="org.apache.struts2.spring.StrutsSpringObjectFactory" />
<constant name="struts.objectFactory.spring.autoWire.alwaysRespect" value="true"/>
or
<constant name="struts.objectFactory" value="spring" />
<constant name="struts.objectFactory.spring.autoWire.alwaysRespect" value="true"/>
source: http://www.javawebdevelop.com/3294124/

Related

Why is Spring 4.0.9 applicationContext initialization getting stuck but not 3.2.1?

My applicationContext initialization was working fine with Spring 3.2.1.
But when I upgraded to 4.0.9 without changing any code or bean definitions), the initialization got stuck. The following statement kept on happening. There's no obvious circular reference though.
Requested bean is currently in creation: Is there an unresolvable circular reference?
I continued to investigate. I deliberately removed a bean definition.
Spring 3.2.1 had the expected outcome: threw a fatal error almost immediately.
Spring 4.0.9 was still getting into this infinite loop, trying to find a different seed bean definition to make things work.
Here's the log statement that kept on happening.
[factory.support.DefaultListableBeanFactory.getTypeForFactoryBean()] - Ignoring bean creation exception on FactoryBean type check:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'someSeedBean-which-is-different-in-every-instance-of-this-log' defined in the class path resource ........ ;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'someDataSource' is defined
What's changed? Any ideas would be helpful.
Bean definitions that work in both Spring 3.x and 4.x
<bean id="abstractDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close" abstract="true" scope="singleton">
<property ....>
</bean>
<bean id="someDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close" scope="singleton" parent="abstractDataSource">
<property name="driverClass" .... />
</bean>
<bean id="someSessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource"> <ref bean="someDataSource" /> </property>
<property name="packagesToScan"> <list>......</list> </property>
....
Bean definitions that work in Spring 3.x but not in 4.0.9.
#Configuration
public class SomeSpringConfiguration{
// Moving this beanDef to Java for features not available in XML
#Bean(destroyMethod = "close")
public DataSource someDataSource() { // also tried setting this to ComboPooledDataSource
// verified that this beanDefinition is recognized by Spring
// but this bean is never created / this method is never executed
...
return datasource;
}
}
<bean class="SomeSpringConfiguration" />
<bean id="someSessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource"> <ref bean="someDataSource" /> </property>
<property name="packagesToScan"> <list>......</list> </property>
....
</bean>
Error I get with Spring 4.0.9 is
Cannot resolve reference to bean 'someSessionFactory' while setting constructor argument;
nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'someSessionFactory':
Requested bean is currently in creation: Is there an unresolvable circular reference?
Please note that the application has thousands of beans defined in/via xml, #Component, and #Configuration. I had to move above bean from xml to a #Configuration class to execute a complicated bean build procedure.
-----------------------UPDATE
I found the issue: 'tons of MethodInvokingFactoryBean[MIB] usages'. For some reason, Spring 4 was getting confused in presence of tons of MIBs. The exact same code base worked fine with Spring 3. I migrated all the logic performed by various MIBs to an ApplicationListener. Please note that ApplicationListener is not an intended replacement for MIBs but in my case I could reproduce the logic in a listener because the MIBs were just performing static injection of Spring beans into classes not managed by Spring. It not only fixed this issue but decreased Spring startup time to ~200 seconds from ~300 seconds.
Unfortunately, I neither could figure out the root cause in Spring nor could reproduce the issue in a smaller code-base (to share here).
Remove
<bean class="SomeSpringConfiguration" />
from XML, it's already annotated with #Configuration. If it's being scanned it's likely the beans in it are getting created twice. You should move everything into Javaconfig.
Circular references are common during development, when you have a lot of beans and are not careful when you autowire them together. The stacktrace should contain the complete list of beans, telling you where the circular reference starts and ends.
I have never seen random circular references (and I encountered circular references many times over the last 7 years)! As far as I know, the code that builds the dependency tree and instantiates/wire the beans is deterministic. So you should always get the same circular reference every time you run. If you don't, I can only thing of two reasons
There is a bug in the Spring version you are using (I'm 99% sure there is a unit test for this)
You have one of more beans that starts a thread as part of bean instantiation, and the thread uses the applicationContext to load another bean lazily (while the context is still loading).
When I teach Spring classes, I recommend that constructors should only contain field assignments, if you need to start threads (or anything else with a lifecycle) you should use the lifecycle methods. Personally I prefer to implement SmartLifeCycle (over InitializingBean/DisposableBean, #PostConstruct/#PreDestroy), since this ensures that nothing will started until after all beans have been instantiated and wired together.
The core of it is as Strelok says, you are mixing annotations and xml config.
The point of the #Configuration annotation is to avoid xml. When you added the component scan for the package after removing SomeSpringConfiguration from xml.
You would start to create multiples of someDataSource, because it is defined in multiple places (#Bean annotation, and in xml).
Please avoid mixing annotations and xml, only use one of them and stick to that, and this problem will, if not resolved but at least much easier to spot.
If you can create an example project and upload it somewhere I can take a closer look if you are still having this issue.

Autowiring fails IllegalArgument un-safe operation exception

I am getting the following exception after upgrading my Spring jars.
org.springframework.web.servlet.DispatcherServlet - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.integration.transformer.HeaderEnricher#4': Cannot create inner bean '(inner bean)' of type [org.springframework.integration.transformer.HeaderEnricher$MessageProcessingHeaderValueMessageProcessor] while setting constructor argument with key [#{partnerHeaderKey}]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#19': Injection of resource dependencies failed; nested exception is java.lang.IllegalArgumentException: Can not set com.follett.fheg.coursemateriallookup.coursematerial.data.dao.PartnerDAO field com.follett.fheg.coursemateriallookup.coursematerial.integration.headerenricher.PartnerHeaderEnricher.partnerDAO to org.springframework.integration.transformer.HeaderEnricher$MessageProcessingHeaderValueMessageProcessor
at org.springframework.beans.factory.support.BeanDefinitionValue Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#19': Injection of resource dependencies failed; nested exception is java.lang.IllegalArgumentException: Can not set com.follett.fheg.coursemateriallookup.coursematerial.data.dao.PartnerDAO field com.follett.fheg.coursemateriallookup.coursematerial.integration.headerenricher.PartnerHeaderEnricher.partnerDAO to org.springframework.integration.transformer.HeaderEnricher$MessageProcessingHeaderValueMessageProcessor
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:306)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1146)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:271)
... 40 more
Caused by: java.lang.IllegalArgumentException: Can not set com.follett.fheg.coursemateriallookup.coursematerial.data.dao.PartnerDAO field com.follett.fheg.coursemateriallookup.coursematerial.integration.headerenricher.PartnerHeaderEnricher.partnerDAO to org.springframework.integration.transformer.HeaderEnricher$MessageProcessingHeaderValueMessageProcessor
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:37)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:57)
at java.lang.reflect.Field.set(Field.java:657)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:150)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:303)
... 44 more
From what I have read I needed to add #Component annotation to my bean and/or create the in my application context - neither of these approaches have worked. The DAO it is referring to is declared like so <bean id="partnerDAO" class="com.follett.fheg.coursemateriallookup.coursematerial.data.dao.impl.PartnerDAOImpl"/>. If I remove the #Component annotation I get a red line under #Autowired and a message that says "Autowired members must be defined in the valid spring bean (#Component/#Service etc..)", but after doing that i still get the errors.
I am using Spring integration so the bean to auto-wire is defined there.
<integration:header-enricher>
<integration:header name="#{partnerHeaderKey}" method="getPartner">
<bean class="com.follett.fheg.coursemateriallookup.coursematerial.integration.headerenricher.PartnerHeaderEnricher"/>
</integration:header>
</integration:header-enricher>
Any thoughts or help is appreciated! Thank you.
Note: the application runs fine if I drop back down to Spring 2.1.4.RELEASE even without declaring the #Component or <bean> in the application context.
UPDATE
As blackpanther mentions below I need a element in the application context. I failed to mention that I DO Have this <context:component-scan base-package="com.follett.fheg.coursemateriallookup.coursematerial.integration.headerenricher" /> There is another for the DAO's as well <context:component-scan base-package="com.follett.fheg.coursemateriallookup.coursematerial.data.dao" />
Not exactly, just putting the annotation #Component does not mean that that Java class will have it's properties autowired. In order to use the #Component annotation effectively, you must tell Spring where to look for these classes. This is done by the <context:component-scan base-package="package.name" /> tag in your Spring configuration.
I would have a look at this article as it may help you.
You can specify #Qualifier on top of the bean declaration inside the component like below.
#Autowired
#Qualifier("loginService")
private ILoginService loginService;
loginService is the name of the bean in the .xml context file.
I was able to resolve this issue by using #Component annotation as well as modifying the way the beans were created in the context.
For some reason when I moved the <bean class=""> out of the <integration:header> and added a ref-"" attribute it started working just fine. I am getting a different error, but I was able to get the application running.
old way
<integration:header-enricher>
<integration:header name="#{partnerHeaderKey}" method="getPartner">
<bean class="com.follett.fheg.coursemateriallookup.coursematerial.integration.headerenricher.Partner HeaderEnricher"/>
</integration:header>
</integration:header-enricher>
new way
<integration:header-enricher>
<integration:header name="#{partnerHeaderKey}" method="getPartner" ref="myBean">
</integration:header>
</integration:header-enricher>
</integration:chain>
<bean id="myBean" class="com.follett.fheg.coursemateriallookup.coursematerial.integration.headerenricher.PartnerHeaderEnricher"/>

Reference an Annotated Spring Component in an XML Bean Definition

I am using an external library that requires that I configure it using an XML Bean definition; in the Bean definition I need to provide an external class with a Bean from my project. I am using spring annotations with component scanning.
How do I reference my annotated Bean within the XML Bean Definition?
Are there any alternatives to creating an XML Bean Definition?
Details: Spring 3.0.7
No matter how it got created (based on XML- or annotation- metadata), every bean ends up in the application context under a unique name.
If you've just annotated your class with #Component or derivatives, without stating any name, the default naming scheme will be applied and the bean name will be your class name with the first character lowercased: ClassName => "className".
With that in mind, if you need to inject that bean in an XML bean definition, you do it like with any other bean in your context:
<bean id="someBean" class="SomeClass">
<property name="someProp" ref="className"/><!-- to stick to the above example -->
</bean>
Since you're mixing annotations with XML, the application context will be able to locate the "className" bean properly.
The #Service annotation takes an optional String value which can be used to give the bean a name of your choosing. For example, if your custom bean looks like:
#Service("mySpecialName")
public class MyClass { ... }
Then your xml could have:
<bean class="com.someone.else.library.SomeClass">
<property name="someProp" ref="mySpecialName"/>
</bean>
Make sure add below code in your xml file
<context:component-scan base-package="" />
<context:annotation-config />

Mocking class in Spring 3.2 causes "No qualifying bean of type X" found

Im trying to mock the HttpClient implementation using the Spring 3.1 profiles and by using EasyMock, but the Spring container complains it cant find a bean with right type. Have I configured the mock wrong? If I replace the EasyMock bean with the actually implementation it is injected correctly, it seems like the EasyMock method doesnt create a bean of right type. All help very appreciated!
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.apache.http.client.HttpClient] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:856)
<beans profile="development,developmentthomas,test,integration,webtest,accept">
<bean id="httpClient" class="org.easymock.EasyMock" factory-method="createMock">
<constructor-arg value="org.apache.http.client.HttpClient" />
</bean>
</beans>
<beans profile="thomasciserver,testserverlocaloleg,testservercioleg,preprod,production,testservercithomas,testserverlocalthomas,localthomasclean,testserver,productionthomas">
<bean id="httpClient" class="org.apache.http.impl.client.DefaultHttpClient"/>
</beans>
i think the problem lies within the factory method.
have a look at this post Autowiring of beans generated by EasyMock factory-method? ithink this will solve your problem
See the spring-test. It has org.springframework.mock.http.client.MockClientHttpRequest. The org.springframework.mock package has a whole bushel of things that will save you from reinventing the wheel.

Understand initialization time behaviour of mvc:annotation-driven

I am trying to debug an issue with RequestMappingHandlerAdapter initialization and I have come to a conclusion by searching the Web that it is getting initialized from mvc:annotation-driven xml entry. Can anyone explain me briefly, how this initialization works i.e. what happens when the parser parses mvc:annotation-driven? Or point me to the code that does it and I will trace it through.
Some more context on this:
I was trying to get RequestMappingHandlerAdapter from the context via autowire but could not. It gave me:
No matching bean of type [org.springframework.web.servlet.mvc.method.annotation.RequestMappingH
andlerAdapter]
expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
Found this thread, but the solution does not does not work: Spring, Jackson and Customization (e.g. CustomDeserializer)
I am using: Spring 3.1.3
This is what my servlet xml file looks like ...
<context:annotation-config />
<context:component-scan base-package="com.xyz" />
<mvc:annotation-driven />
Thanks,
Parth
I would think it would cause either the AnnotationConfigApplicationContext or AnnotationConfigWebApplicationContext to search for the annotated classes and create/graph them. One way to figure things out would be to make a bean that throws a RuntimeException in its default constructor and see what the stack trace looks like.

Resources