问题
Details of jars used: Struts2 2.2.1 Spring 3.0.5.RELEASE Hibernate 3.6.0.FINAL
I am experiencing a strange issue when trying to execute an action mapped as follows:
<action name="supplierSearch" class="supplierSearchAction">
<result>/pages/suppliersearch.jsp</result>
</action>
<action name="searchForSupplier" class="supplierSearchAction" method="doSearch">
<result>/pages/suppliersearch.jsp</result>
</action>
the first action sends the user to a search page, they enter a search string and then the second action is invoked when the post the form.
The action in spring config is as follows:
<bean id="supplierSearchAction"
class="com.blah.SupplierSearchAction"
scope="prototype">
<property name="searchService" ref="supplierSearchService"></property>
</bean>
the search service uses hibernate search and is defined as follows:
<bean id="supplierSearchService"
class="com.devcentre.yubi.application.service.SupplierSearchServiceImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
I am using spring aop to configure my transaction boundaries and the persistence config is as follows:
<tx:annotation-driven transaction-manager="txManager" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
// annotated classes here
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect"> org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">upgrade</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.provider_class">
net.sf.ehcache.hibernate.SingletonEhCacheProvider</prop>
<prop key="hibernate.search.default.directory_provider">org.hibernate.search.store.FSDirectoryProvider
</prop>
<prop key="hibernate.search.default.indexBase">/lucene/indexes</prop>
<prop key="hibernate.search.default.batch.merge_factor">10</prop>
<prop key="hibernate.search.default.batch.max_buffered_docs">10</prop>
</props>
</property>
</bean>
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
Spring is configured as follows in my web.xml:
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/src/spring-config.xml
/WEB-INF/src/persistence-config.xml
</param-value>
</context-param>
On the search JSP page I have a form which submits the search string to the action which should invoke the doSearch method. However, when I submit the search I get an exception as follows (because devmode is enabled):
Struts has detected an unhandled exception:
Messages: $Proxy28.doSearch()
File: java/lang/Class.java Line
number: 1,605
and then the stack trace:
java.lang.NoSuchMethodException: $Proxy28.addComponent()
java.lang.Class.getMethod(Class.java:1605)
org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.getActionMethod(AnnotationValidationInterceptor.java:75)
org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:47)
com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
This is very odd because there is a method on the action class with the signature:
public String doSearch()
Can anyone help shed light on why the ActionProxy doesn't have the expected method?
Thanks,
Alex
回答1:
java.lang.NoSuchMethodException: $Proxy25.doSearch()
Notice that the name of your action class is $Proxy25. It appears that something is creating a dynamic proxy to your action class. This is usually seen when using Aspect Oriented Programming (AOP) method interceptors on methods of a class — e.g., for things like transactions.
For example, I use Google Guice from time-to-time and when using AOP method interceptors on methods of a class, an action called LoginAction
would have a dynamic proxy created called LoginAction$$EnhancerByGuice$$someAdditionalCharacters
. While this dynamic proxy subclasses the methods of the class, it does not inherit annotations. My guess is that the same thing is happening here.
I don't use Spring, so I am not familiar with what libraries it uses to create dynamic proxies.
Update
If you remove the AOP annotations from your action class, then it should work as expected. Your action class can delegate to a service-layer class to handle persisting to the database (you can put the @Transactional
annotation on that class's method(s)).
回答2:
The struts2 spring & annotation integration seems to have its catches still...
the first call to getMethod from the AnnotationValidationInterceptor can be avoided using exclude parameters.
<interceptor-ref name="validation">
<param name="excludeMethods">YOURMETHODHERE</param>
</interceptor-ref>
however, this simply postpones the problem until the actual method is called by the DefaultActionInvocation ending up at the same code location (getMethod Class#1597) which fails with the given method name on the proxy.
WORKAROUND
The only functional workaround I found was to use the standard execute() method for the action and split the actions up into different classes.
Hope that helps.
来源:https://stackoverflow.com/questions/5831855/nosuchmethodexception-thrown-by-annotationvalidationinterceptor-when-executing-a