Announcement Announcement Module
Collapse
No announcement yet.
BeanNotOfRequiredTypeException using ServiceLocatorFactoryBean and @Transactional Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • BeanNotOfRequiredTypeException using ServiceLocatorFactoryBean and @Transactional

    I'm running into a problem using the ServiceLocatorFactorBean, where my locator interface returns an object that is marked @Transactional. Here is a summarized version of my prototype object:

    Code:
    @Component("rebuildActionIndexThread")
    @Scope("prototype")
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public class RebuildActionIndexThread extends Thread {
    	@Resource
    	private IndexService indexService;
    
    	@Override
    	public void run() {
    		indexService.rebuildIndex();
    	}
    }
    And my locator interface:

    Code:
    public interface IndexThreadFactory {
    	public RebuildActionIndexThread getRebuildActionIndexThread(String id);
    }
    With its corresponding bean definition:

    Code:
    <bean id="indexThreadFactory" class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean" p:serviceLocatorInterface="mil.whs.eccs.tools.service.IndexThreadFactory"/>
    In another service, calling

    Code:
    RebuildActionIndexThread t = indexThreadFactory.getRebuildActionIndexThread("rebuildActionIndexThread");
    Causes a BeanNotOfRequiredTypeException to be thrown.

    Code:
    org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'rebuildActionIndexThread' must be of type [mil.whs.eccs.tools.service.impl.RebuildActionIndexThread], but was actually of type [$Proxy526]
            at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
            at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
            at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:168)
            at org.springframework.beans.factory.config.ServiceLocatorFactoryBean$ServiceLocatorInvocationHandler.invokeServiceLocatorMethod(ServiceLocatorFactoryBean.java:368)
            at org.springframework.beans.factory.config.ServiceLocatorFactoryBean$ServiceLocatorInvocationHandler.invoke(ServiceLocatorFactoryBean.java:358)
            at $Proxy516.getRebuildActionIndexThread(Unknown Source)
            at mil.whs.eccs.tools.service.impl.IndexServiceImpl.startRebuildingIndex(IndexServiceImpl.java:57)
    If I remove the @Transactional annotation from RebuildActionIndexThread, everything works fine. I have the component scanner with the scoped-proxy="targetClass" attribute set, so obviously a transactional proxy of RebuildActionIndexThread is returned from the call to IndexThreadFactory.getRebuildActionIndexThread, but shouldn't that proxy be a subclass of, and thus survive the cast to, RebuildActionIndexThread?

  • #2
    I suggest you use the search as this question has been answered about a 1000 times. (And we are going to add another one).

    I suggest you read chapter 6 of the reference guide, especially 6.6.1 which explains how it works. First off all it is recommended that you programm to interfaces, judging from your expeption you aren't doing that. Next to that it is a bad practice to extend Thread it is recommended to implement Runnable (which should also solve your problem). You would need to modify your code a little, but I recommend using a TaskExecutor instead of launching your own threads (you can simply add the Runnable to the queue for execution).

    Comment


    • #3
      I actually did spend quite a bit of time searching, and found nothing helpful. For a question that has been answered "1000s of times", startlingly few (like, 0) of those answers addressed a BeanNotOfRequiredTypeException. I have read section 6.6.1 in docs, so if we could do away with the ideas that I either have not done my homework or am an idiot, that would be nice. I did not ask for best practice advice regarding programming to interfaces or the best way to start a thread. You gave me both without answering my question.

      According to my understanding of section 6.6.1, since I forced a CGLIB proxy of my class to be created, the proxy should be a subclass of my class and therefore survive a cast to it. However, that is not happening. If you could explain why without being condescending, I would very much appreciate it.

      Comment


      • #4
        Originally posted by unkelkalub
        You gave me both without answering my question.
        I gave you a solution to your problem and with it even giving you some free advice on improving your program. But if you don't want to follow best practices...

        The problem comes from the fact that you are proxying a proxy (unknowingly but that is what is happening) due to a Scoped AND transactional proxy. The scoped proxy is a CGLIB proxy, the transactional one is a JDKProxy (only implementing the interfaces which Thread also implements).

        Originally posted by unkelkalub
        ... I have the component scanner with the scoped-proxy="targetClass" //
        The property should give away that it concerns the scoped-proxy here. Transactional proxies are created by the tx:annotation-driven which has a proxy-target-class property (which by default is false).

        The easiest solution is the one which I already gave you (follow best practices), which you rejected...

        Originally posted by unkelkalub
        I actually did spend quite a bit of time searching, and found nothing helpful. For a question that has been answered "1000s of times", startlingly few (like, 0) of those answers addressed a BeanNotOfRequiredTypeException.
        Searching for the error message instead of the actual exception will give you quite a few hits (you might want to limit the name to proxy$ because that is a dynamic classname).
        Last edited by Marten Deinum; Jan 19th, 2009, 04:37 PM.

        Comment


        • #5
          Thanks for taking the time to explain this. Based on this explanation at the end of section 6.6:

          To be clear: using 'proxy-target-class="true"' on <tx:annotation-driven/>,
          <aop:aspectj-autoproxy/> or <aop:config/> elements will force the use of CGLIB
          proxies for all three of them.
          I mistakenly thought that specifying scoped-proxy="targetClass" would apply to every kind of proxy configuration. Obviously, that explanation does not mention the context:component-scan element, and I should have read it more carefully.

          I do appreciate your advice and am not rejecting any of it. I was trying to gain the deepest understanding of my mistake that I could. You giving me a solution without an explanation, while generous, would have left me open to making a similar mistake in a different context. I just don't like knowing what to do without why.

          Thanks again.
          Last edited by unkelkalub; Jan 19th, 2009, 11:36 PM.

          Comment

          Working...
          X