NoSuchMethodException thrown by AnnotationValidationInterceptor when executing an action - spring

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

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

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.

Related

Spring Interceptors are called twice in mixed configuration (annotation-based and SimpleUrlHandlerMapping)

We have a Spring web application with mixed configuration for Spring 2.x and Spring 3.1 mvc objects. There are same set of interceptors defined by mvc:interceptors tag and SimpleUrlHandlerMapping interceptor property. Our thought was that each handler mapping applies its own interceptors only, but we notice that on Spring 2 urls the interceptors are called twice. When we remove the interceptors from the SimpleUrlHandlerMapping the interceptors are still applied which means mvc:interceptors are effective anyway. Below please see the snippet of configuration:
mvc-config.xml
<mvc:annotation-driven />
<mvc:interceptors>
<ref bean="clientDataInterceptor" />
<ref bean="securityInterceptor" />
<ref bean="resourceCleanupInterceptor" />
</mvc:interceptors>
springdispatcher.xml
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="alwaysUseFullPath" value="true"/>
<property name="mappings">
<props>
<prop key="/path/**">myController</prop>
...
</props>
</property>
<property name="interceptors">
<list>
<ref bean="clientDataInterceptor" />
<ref bean="securityInterceptor" />
<ref bean="resourceCleanupInterceptor" />
</list>
</property>
</bean>
web.xml
<servlet>
<servlet-name>springdispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springdispatcher.xml, /WEB-INF/mvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Appreciate any insight why this is happening and if it is safe to simply remove Spring 2.x interceptor list.
You have a handler mapping that matches some URLs (like /path/** in your case). Also, you can have another handler mapping that matches some other URLs (like BeanNameUrlHandlerMapping mapping to bean names or SimpleUrlHandlerMapping). The point is that with your mappings you define associations between URLs and handlers. <mvc:interceptors/> apply to all URLs if no include or exclude patterns are defined.
I looked in the source code here and especially here and if there are no excludePatterns defined then code goes on and checks for includePatterns. If these are null, as well, then the interceptor matches. So, I'm reading this that if I define an interceptor using <mvc:interceptors/> and I'm not giving it any patterns to include or exclude then that interceptor applies to all URLs.

Request scoped bean inside a Singleton bean

I have a web app where i define 2 bean
1 with a singleton scope and one with a request scope.
I need the request scoped bean inside the singleton bean.
So i ended up with this
<bean id="routingDataSource" class="org.ai2l.ifsr.service.multiTenants.RoutingDataSource" scope="request">
<aop:scoped-proxy/>
<property name="targetDataSources" value="#{tenantSpecificDependencyFactory.tenantIdToDataSource}"/>
<!-- <property name="defaultTargetDataSource" ref="parentDataSource"/> -->
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="ifsrPU"/>
<property name="dataSource" ref="routingDataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="${hibernate.dialect}"/>
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.ejb.naming_strategy">
org.hibernate.cfg.ImprovedNamingStrategy
</prop>
</props>
</property>
</bean>
As you will notice i've use the <aop:scoped-proxy/>but it isn't working.
I've also tryed the
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
inside my web.xml. But none of this is working.
I still get this error
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
Does any one know why this happens??

Hibernate 4 + Spring 3, No Inserts or Updates

In order to work around Hibernate bug HHH-2763, I'm trying to update my app from Hibernate 3 to Hibernate 4. It seemed to have gone smoothly until I realized that while my application can read data, it never seems to do inserts or updates. I turned on SQL logging: under Hibernate 3, there are inserts and updates. Under Hibernate 4, there are no inserts and updates.
We were doing explicit flushes in Hibernate 3 by overriding the OpenSessionInViewFilter class' closeSession method as follows:
public void closeSession(Session session, SessionFactory sessionFactory) {
session.flush();
super.closeSession(session, sessionFactory);
}
But in Hibernate 4, this is no longer an option because that method no longer exists.
My Hibernate 4 configuration for the Session Factory and Transaction Manager follows:
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.default_schema">${oracle.default_schema}</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.generate_statistics">false</prop>
<prop key="hibernate.show_sql">${hibernate.showSql}</prop>
<prop key="hibernate.use_sql_comments">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
<property name="mappingResources">
<list> . . . </list>
</property>
<property name="annotatedClasses">
<list> . . . </list>
</property>
</bean>
<!-- Configure transaction management, enabling #Transactional annotations -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<property name="nestedTransactionAllowed" value="true" />
</bean>
(Edit) And here's the configuration of the OpenSessionInViewFilter:
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>
org.springframework.orm.hibernate4.support.OpenSessionInViewFilter
</filter-class>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactory</param-value>
</init-param>
</filter>
My guess is that it's not flushing and committing. But why?
what do you mean by "But in Hibernate 4, this is no longer an option because that method no longer exists"?
spring comes with a OpenSessionInViewFilter for hibernate 4, which is:
org.springframework.orm.hibernate4.support.OpenSessionInViewFilter
are you still using?
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
try the new OpenSessionInViewFilter for hibernate 4
edit...
You do not have to flush the session manually, transcation manager will take care of it, as the javadoc of hibernate4 OpenSessionInViewFilter says:
The active transaction manager will temporarily change the flush mode
to FlushMode.AUTO during a read-write transaction, with the flush
mode reset to FlushMode.NEVER at the end of each transaction.
you can change you log level to TRACE, and check the console to make sure flush mode is set to AUTO:
... setting flush mode to: AUTO
or can you post your save/update code fragment?

hibernate.search.default.directory_provider in spring beans rather than persistence.xml

I am in a rather nasty situation. We use compass for Hibernate search integration with Lucene and have implemented database directory search (using JdbcDirectory) instead of FSDirectoryProvider, RAMDirectoryProvider etc.
The problem is that the directory provider is passed as a property inside the META-INF/persistence.xml like the one below:
<property name="hibernate.search.default.directory_provider" value="uk.company.package.JdbcDirectoryProvider" />
We need to pass the database details to the the JdbcDirectoryProvider as JdbcDirectory requires a datasource to be passed.
We are constructing the datasource (for the directory provider) in an unconventional way using a property file (in the class path) with the database and index details.
If we have uk.company.JdbcDirectoryProvider configured as a spring bean, we can inject the datasource. This works well with Tomcat but not with OAS or Weblogic as still as we are passing the directory_provider in the persistence.xml. Probably becasue the datasource is initialized by the spring (becasue of the way classloaders work in these app servers).
My question is how can we configure the hibernate.search.default.directory_provider directly inside aSpring bean instead of the persistence.xml?
The closest place is:
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
But it only takes three properties:
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
Solution
You could pass the hibernate properties in spring bean as jpaProperties
<property name="jpaProperties">
<props>
<prop key="hibernate.search.default.directory_provider">
uk.company.package.JdbcDirectoryProvider
</prop>
</props>
</property>
I found the solution.
You could pass the hibernate properties in spring bean as jpaProperties
<property name="jpaProperties">
<props>
<prop key="hibernate.search.default.directory_provider">
uk.company.package.JdbcDirectoryProvider
</prop>
</props>
</property>

Access Spring Web MVC Exception Resolver from Spring Security Context

I have a Spring Web MVC configuration with a SimpleMappingExceptionResolver in it to handle some access exceptions:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" p:defaultErrorView="uncaughtException">
<property name="exceptionMappings">
<props>
<prop key=".DataAccessException">dataAccessFailure</prop>
<prop key=".NoSuchRequestHandlingMethodException">resourceNotFound</prop>
<prop key=".TypeMismatchException">resourceNotFound</prop>
<prop key=".MissingServletRequestParameterException">resourceNotFound</prop>
</props>
</property>
</bean>
I also have a Spring Security context configuration where I would like to handle some authentication related exceptions. Currently, I have an ExceptionMappingAuthenticationFailureHandler set up as follows:
<form-login authentication-failure-handler-ref="exceptionMapper" ... />
...
<bean id="exceptionMapper" class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler" >
<property name="exceptionMappings">
<props>
<prop key=".CredentialsExpiredException">/resetPassword</prop>
<prop key=".BadCredentialsException">/login?failure=true</prop>
</props>
</property>
</bean>
I was thinking that it would be nice to consolidate these into a single exception handling configuration by moving the security mappings to the MVC configuration. My problem is that I don't know how to tell Spring Security that I want form-login's authentication-failure-handler to use the resolver.
I can't just add an id to SimpleMappingExceptionResolver because 1) authentication-failure-handler-ref expects a Handler, not a Resolver, and 2) any beans that are defined in the MVC configuration don't seem to be visible from the security context...
Thanks for any help!
To answer part 2) of your question, you can share bean definitions between configurations via the use of the <import resource="..."/> tag.
I'm not sure how successful you will be for part 1) (single exception resolver), because having looked at the API both classes are completely different - no shared interface. You may have to roll your own, using one of the classes as the platform and building the functionality of the other class into it.

Resources