NoSuchMethodException thrown by AnnotationValidationInterceptor when executing an action
Asked Answered
O

2

0

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

Operon answered 29/4, 2011 at 12:13 Comment(8)
Dou you use both Struts2 and Spring?Dicot
Yep. Both used with great success up until nowOperon
Update, I seem to have lots more validation problems at the moment. On another action I have a method annotated with @SkipValidation. However, this is not being respected and I am getting a Null Pointer Exception when the validate() method is executed (when it shouldn't be). This was working about two days ago!Operon
In struts.xml do you have <constant name="struts.devMode" value="true" />? If so what messages does it print?Hash
Hey thanks for your interest. It is as follows: java.lang.NoSuchMethodException: $Proxy25.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) this is driving me crazy because this method exists.Operon
I am having another problem with an action which was working a few days ago. This has @SkipValidation on the execute() method and now the AnnotationValidationInterceptor cannot find the annotation on the action proxy so calls validate() when it shouldn't. Can you see how this strange action proxy behaviour might have come about?Operon
It normally prints several messages before the exception list. Please edit the original answer to add long content. Please show your web.xml (to see how spring was added). Also do you have to wire in your actions? I use struts2.2.1.1 and spring 3.0.5 but have not found a reason to wire in the actions themselves. Have you checked the documentation for the struts2-spring-plugin to make sure you have it initially configured correctly?Hash
I have edited the original question. I do define the actions and their dependencies in the spring config and then use the spring bean id as the action class in the struts.xml file. I haven't managed to make this work without linking the definitions together in this way.Operon
I
2

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)).

Incandescent answered 30/4, 2011 at 1:0 Comment(6)
Steve, Thanks for your reply. I am using the spring plugin and have not made any modifications to the object factory. I am using @Transactional annotations on some of my action methods (save for example). However, this dynamic proxy which is created doesn't seem to have the expected methods on it. So I define an action which should invoke the doSearch() method and the AnnotationValidator tries to find it to look for @SkipValidation annotations but fails because the proxy lacks that method. I have updated the question with more detail.Operon
I've revised my answer. The missing annotation is expected due to the proxy, but the method should be there. Strange.Incandescent
Steve, You are a genius. I have just removed the @Transactional annotations from all of my affected action classes put them on to the DAOImpl class methods. This seems to have fixed the ignored @SkipValidation and missing method problems on the Proxy. I don't have an explanation regarding the missing method. But, hurrah. Thank you.Operon
Further update, the proxy class being generated is a JDKDynamicProxy. This is interface based. My additional action method doSearch() is not on an interface implemented by my action therefore it is not proxied. I can fix this by setting the proxyTargetClass to true on the spring ProxyFactoryBean. This will force spring to use CGLIB to proxy my action and will not require me to code to an interface. That said, perhaps that's a code smell and should be address rather than hidden.Operon
Seen before here:Operon
Good find on the JDKDynamicProxy. Glad that I could help you out.Incandescent
S
0

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.

Sept answered 15/6, 2011 at 15:57 Comment(1)
Thanks for your interest, this issue was resolved by the posts above by Steven about a month and a half ago. The issue was due to including an @Transactional annotation on the action class.Operon

© 2022 - 2024 — McMap. All rights reserved.