Announcement Announcement Module
Collapse
No announcement yet.
JdbcTemplate injection error Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • JdbcTemplate injection error

    I had a much more detailed post written up about this with more code samples and all, but this posting system is not letting me post it because it is detecting non-existent "URLs to other sites" in it. So here's a short version. Will get to the longer one soon:

    Summary: Cannot inject JdbcTemplate into any JDBC-backed (JdbcDaoSupport) DAOs if we use the new aop config/tx advice declarative way of managing transactions. We have a mix of HibernateDaoSupport and JdbcDaoSupport DAOs and want to make our service layer which calls this transactional. Our transaction manager is a HibernateTransactionManager. As soon as we wire in the aop pointcut for service methods and a tx advice to go with it (cannot post code yet because the system won't let me), we run into:

    Error:
    Code:
    org.springframework.beans.TypeMismatchException: Failed to convert property value of type [$Proxy57 implementing org.springframework.jdbc.core.JdbcOperations,org.springframework.beans.factory.InitializingBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [org.springframework.jdbc.core.JdbcTemplate] for property 'jdbcTemplate'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [$Proxy57 implementing org.springframework.jdbc.core.JdbcOperations,org.springframework.beans.factory.InitializingBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [org.springframework.jdbc.core.JdbcTemplate] for property 'jdbcTemplate': no matching editors or conversion strategy found
    	at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:391)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.convertForProperty(AbstractAutowireCapableBeanFactory.java:1288)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1249)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1010)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:472)
    	... 131 more
    Annotation-based transactions work fine.

    Any pointers appreciated. Will get to the more detailed post soon.

    Much obliged,

    Uqbar

  • #2
    The reason is that JDK proxies are used. Just switch to cglib proxying by adding 'proxy-target-class="true' attribute to your <aop:config> element.

    Comment


    • #3
      Thanks much. That did address the main issue I was having. I do run into another one now, but that one is probably more easily addressed:

      Code:
      org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.mchange.v2.c3p0.ComboPooledDataSource]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class com.mchange.v2.c3p0.ComboPooledDataSource
      I guess I need to look for some other connection pooling framework that is cglib-instrumentable.

      Comment


      • #4
        Well looks like using the declarative approach is unsupportable, for me anyway. Even switching to a non-final class for the conn pool, I now run into the same issue with the Hibernate session factory:

        Code:
        org.springframework.aop.framework.AopConfigException:
        Could not generate CGLIB subclass of class [class org.hibernate.impl.SessionFactoryImpl]: 
        Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: 
        Cannot subclass final class class org.hibernate.impl.SessionFactoryImpl
        That's one class I cannot swap out for anything, so unless I am doing something dramatically wrong, I guess the @Transaction annotation is the only workable solution. If it cannot deal with basic Hibernate classes like the SessionFactory, I fail to see how this can ever work.

        (I get why it is not working, I just can't see how this could ever work, though the documentation seems quite confident that it does).

        Comment


        • #5
          The problem is that once you specify proxy-target-class="true", Spring uses CGLIB proxies for every bean that needs to be proxied. So even in the case of SessionFactoryImpl, it tries to use CGLIB proxies and fails.

          You may want to go the following route:
          1. Don't specify proxy-target-class="true" (i.e. use default 'false')
          2. Inject JdbcOperation instead of JdbcTemplate.

          -Ramnivas

          Comment


          • #6
            Originally posted by uqbar View Post
            That's one class I cannot swap out for anything, so unless I am doing something dramatically wrong, I guess the @Transaction annotation is the only workable solution. If it cannot deal with basic Hibernate classes like the SessionFactory, I fail to see how this can ever work.

            (I get why it is not working, I just can't see how this could ever work, though the documentation seems quite confident that it does).
            As Ramnivas said, Spring AOP uses a single proxying mechanism for all aspects - JDK or CGLIB proxies. However, you can exploit either load- or compile-time AspectJ weaving in order to inject aspects logic.

            Comment


            • #7
              Well, this is getting way more complex than the docs had me believe. Is there any way to tell it to selectively proxy beans - like just the ones being adviced? I am not sure why the presence <aop:config> decides to proxy every bean in the factory.

              Reason this is rapidly becoming a medium-sized headache is that though @Transactional works, we need some additional advice around these transactional pointcuts, for profiling/logging, etc. Earlier these were configuted as pre/postInterceptors around the old-style TransactionProxyFactoryBean, and the newer way of doing that involves an <aop:config> again. I think the old TPFB way is a lot better now.

              I could work around the JdbcTemplate/JdbcOperations but aside from the fact that it will involve a LOT of code migration, I am sure it will complain about some other class once I fix this one. I just need this to not attempt to proxy every bean in the universe, just the ones that are adviced and need proxying.

              Comment


              • #8
                <aop:config> will lead to creating proxy for only beans that may have an advice applied. Effectively, your pointcuts determine if a bean gets proxied.

                -Ramnivas

                Comment


                • #9
                  Must have interfaces on transactional classes

                  I've added some carriage returns for readability, but I was having the same error, and after much playing around, I discovered the solution. The error was similar (and I'll post the solution right after this pasted in error):

                  org.springframework.beans.factory.BeanCreationExce ption:
                  Error creating bean with name 'accountServiceImpl' defined in file
                  [C:\Tomcat5.5\webapps\ROOT\WEB-INF\classes\applicationContext-AOP.xml]:

                  Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException:
                  Failed to convert property value of type [
                  $Proxy8 implementing
                  org.springframework.beans.factory.InitializingBean ,
                  org.springframework.aop.SpringProxy,
                  org.springframework.aop.framework.Advised
                  ]
                  to required type [com.equilibrium.apv.common.ibatis.AccountDAO] for property 'accountDAO';

                  nested exception is java.lang.IllegalArgumentException: Cannot convert value of type
                  [$Proxy8 implementing org.springframework.beans.factory.InitializingBean ,
                  org.springframework.aop.SpringProxy,
                  org.springframework.aop.framework.Advised
                  ] to required type [com.equilibrium.apv.common.ibatis.AccountDAO] for property 'accountDAO':
                  no matching editors or conversion strategy found

                  ----------------
                  So what appears to be happening is that the spring framework is attempting to cast classes to be wrapped AOP objects (proxies), but it keeps failing. I tried using @Transactional annotations, and I tried <aop:config, but still kept getting these types of errors. What finally worked was to put interfaces on any of the classes that I wanted to put @Transacational into. Apparently the AOP framework is trying to proxy the objects/classes, but it can't do that with direct classes, which kind of makes sense, because it can do introspection and make the wrapped object implement an interface and extend the proxy, but it can't do that if it's a direct object. I'm guessing that this is going on, but what I do know is that when I added interfaces to all my classes that I want to use, and also make sure that any bean that's referencing another bean is using the interface for the getters and setters, then all the problems go away and it works great.

                  Comment


                  • #10
                    Originally posted by jdestremps View Post
                    Apparently the AOP framework is trying to proxy the objects/classes, but it can't do that with direct classes, which kind of makes sense, because it can do introspection and make the wrapped object implement an interface and extend the proxy, but it can't do that if it's a direct object...
                    Sorry but you're wrong. 6.6. Proxying mechanisms:

                    If the target object to be proxied implements at least one interface then a JDK dynamic proxy will be used. All of the interfaces implemented by the target type will be proxied. If the target object does not implement any interfaces then a CGLIB proxy will be created.

                    If you want to force the use of CGLIB proxying (for example, to proxy every method defined for the target object, not just those implemented by its interfaces) you can do so

                    Comment

                    Working...
                    X