Announcement Announcement Module
Collapse
No announcement yet.
Spring gives me $Proxy19 instead of a bean. Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring gives me $Proxy19 instead of a bean.

    I use latest stable Spring release.
    I have a following problem with it:

    I have 3 simple classes:
    BugThrower (references BasicController)
    BasicController (references BasicDAO)
    BasicDAO (references PersistenceContext)
    (Code below)

    in my applicationContext they are described as follows:
    <bean id="basicDAO" class="colere.model.util.BasicDAO" />
    <bean id="basicController" class="colere.model.util.BasicController" />
    <bean id="bug" class="colere.model.test.BugThrower" />

    Running this code produces an error:
    package colere.model.test;
    import org.springframework.context.support.*;
    import org.springframework.beans.factory.xml.*;
    import org.springframework.core.io.ClassPathResource;
    import colere.model.util.*;
    public class TestRun {
    static public void main(String[] args) {
    GenericApplicationContext ctx = new GenericApplicationContext();
    XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
    xmlReader.loadBeanDefinitions(new ClassPathResource("META-INF/applicationContext.xml"));
    ctx.refresh();
    }
    }

    Stack trace:
    Exception in thread "main" org.springframework.beans.factory.BeanCreationExce ption: Error creating bean with name 'bug' defined in class path resource [META-INF/applicationContext.xml]: Error setting property values; nested exception is org.springframework.beans.PropertyBatchUpdateExcep tion; nested PropertyAccessExceptions (1) are:
    PropertyAccessException 1: org.springframework.beans.TypeMismatchException: Failed to convert property value of type [$Proxy19] to required type [colere.model.util.BasicController] for property 'basicController'; nested exception is java.lang.IllegalArgumentException: No matching editors or conversion strategy found
    Caused by: org.springframework.beans.PropertyBatchUpdateExcep tion; nested PropertyAccessException details (1) are:
    PropertyAccessException 1:
    org.springframework.beans.TypeMismatchException: Failed to convert property value of type [$Proxy19] to required type [colere.model.util.BasicController] for property 'basicController'; nested exception is java.lang.IllegalArgumentException: No matching editors or conversion strategy found
    Caused by: java.lang.IllegalArgumentException: No matching editors or conversion strategy found
    at org.springframework.beans.TypeConverterDelegate.co nvertIfNecessary(TypeConverterDelegate.java:212)
    at org.springframework.beans.TypeConverterDelegate.co nvertIfNecessary(TypeConverterDelegate.java:127)
    at org.springframework.beans.BeanWrapperImpl.setPrope rtyValue(BeanWrapperImpl.java:774)
    at org.springframework.beans.BeanWrapperImpl.setPrope rtyValue(BeanWrapperImpl.java:607)
    at org.springframework.beans.AbstractPropertyAccessor .setPropertyValue(AbstractPropertyAccessor.java:49 )
    at org.springframework.beans.AbstractPropertyAccessor .setPropertyValues(AbstractPropertyAccessor.java:7 4)
    at org.springframework.beans.AbstractPropertyAccessor .setPropertyValues(AbstractPropertyAccessor.java:5 7)
    at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.applyPropertyValues(Abs tractAutowireCapableBeanFactory.java:965)
    at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.populateBean(AbstractAu towireCapableBeanFactory.java:740)
    at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.createBean(AbstractAuto wireCapableBeanFactory.java:417)
    at org.springframework.beans.factory.support.Abstract BeanFactory$1.getObject(AbstractBeanFactory.java:2 45)
    at org.springframework.beans.factory.support.DefaultS ingletonBeanRegistry.getSingleton(DefaultSingleton BeanRegistry.java:140)
    at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:242)
    at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:156)
    at org.springframework.beans.factory.support.DefaultL istableBeanFactory.preInstantiateSingletons(Defaul tListableBeanFactory.java:273)
    at org.springframework.context.support.AbstractApplic ationContext.refresh(AbstractApplicationContext.ja va:346)
    at colere.model.test.TestRun.main(TestRun.java:23)


    Please help! What am I doing wrong?


    ----- - BugThrower ----
    package colere.model.test;
    import colere.model.util.*;
    public class BugThrower {
    BasicController basicController;
    public BasicController getBasicController() { return basicController; }
    public void setBasicController(BasicController basicController) { this.basicController = basicController; }
    }
    ------ BasicController -------------
    package colere.model.util;
    import javax.persistence.*;
    import java.util.*;
    import org.springframework.transaction.annotation.*;

    @Transactional
    public class BasicController implements IBasicController {
    private BasicDAO basicDAO;
    public List query(String queryString, Object... params) {
    return basicDAO.query(queryString, params);
    }
    public void setBasicDAO(BasicDAO basicDAO) {
    this.basicDAO = basicDAO;
    }
    public void store(Object o) {
    this.basicDAO.store(o);
    }
    }



    ------- BasicDAO ----------------------------------------------------
    package colere.model.util;

    import javax.persistence.*;
    import java.util.*;
    public class BasicDAO {
    private EntityManager entityManager;

    @PersistenceContext(unitName="colere")
    public void setEntityManager(EntityManager entityManager) {
    this.entityManager = entityManager;
    }

    public List query(String queryString, final Object... params) {
    Query query = entityManager.createQuery(queryString);
    setParameters(query, params);
    return query.getResultList();
    }

    public boolean isOpen() {
    return entityManager.isOpen();
    }
    private void setParameters(Query q, Object[] params) {
    int i;
    for (i=0; i<params.length; i++) {
    q.setParameter(1+i, params[i]);
    // ordinals are 1-based
    }
    }
    public void store(Object o) {
    entityManager.persist(o);
    }
    }

  • #2
    Looks like you are using autowiring support. Try actually doing the wiring explicitly to see if you still get the error.

    Code:
    <bean id="basicDAO" class="colere.model.util.BasicDAO" />
    <bean id="basicController" class="colere.model.util.BasicController">
        <property name="basicDao" ref="basicDao"/>
    </bean>
    <bean id="bug" class="colere.model.test.BugThrower">
      <property name="basicController" ref="basicController" />
    </bean>
    Also try modifying how you are loading the application context.

    Code:
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("META-INF/applicationContext.xml");
    For future reference but code snipplets within [C O D E] [/C O D E] blocks (without spaces). Makes it easier to read.

    Comment


    • #3
      thank You for a reply.
      Originally posted by cwash5 View Post
      Looks like you are using autowiring support. Try actually doing the wiring explicitly to see if you still get the error.
      I tried it, but the error is still here. Seems that autowiring is doing it's job well. I even tried to change field/class names to exclude some weird name collisions or to fool Spring and it does what it should, unfortunately, it tries to inject a proxy instead of required class.

      Maybe my configuration is wrong in some way? Do I need special VM support for proxies? I use:
      Java(TM) 2 Runtime Environment, Standard Edition (build diablo-1.5.0-b00)
      Maybe assigning a Proxy to a property of some type should not lead to cast errors?

      Maybe I can turn on some additional logging/debug in spring to track this ?

      my xml config is changed to:
      Code:
          <bean id="basicDAO" class="colere.model.util.BasicDAO" />
          <bean id="basicController" class="colere.model.util.BasicController">
              <property name="basicDAO" ref="basicDAO" />
          </bean>
          <bean id="bug" class="colere.model.test.BugThrower" >
              <property name="basicController" ref="basicController"/>
          </bean>
      The exception is the same.
      There is some info Spring prints out at the beginning, maybe it can be helpful (there is something about "not eligible for auto-proxying"...):
      Code:
      INFO: Loading XML bean definitions from class path resource [META-INF/applicationContext.xml]
      2006-12-23 16:33:07 org.springframework.context.support.AbstractRefreshableApplicationContext refreshBeanFactory
      INFO: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext;hashCode=20471808]: org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans [entityManagerFactory,dataSource,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor,org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor,basicDAO,basicController,bug]; root of BeanFactory hierarchy
      2006-12-23 16:33:07 org.springframework.context.support.AbstractApplicationContext refresh
      INFO: 9 beans defined in application context [org.springframework.context.support.ClassPathXmlApplicationContext;hashCode=20471808]
      2006-12-23 16:33:07 org.springframework.aop.framework.DefaultAopProxyFactory <clinit>
      INFO: CGLIB2 available: proxyTargetClass feature enabled
      2006-12-23 16:33:07 org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization
      INFO: Bean 'org.springframework.aop.config.internalAutoProxyCreator' is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
      2006-12-23 16:33:08 org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization
      INFO: Bean 'org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor' is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
      2006-12-23 16:33:08 org.springframework.context.support.AbstractApplicationContext initMessageSource
      INFO: Unable to locate MessageSource with name 'messageSource': using default [[email protected]be]
      2006-12-23 16:33:08 org.springframework.context.support.AbstractApplicationContext initApplicationEventMulticaster
      INFO: Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default [org.[email protected]1e58cb8]
      2006-12-23 16:33:08 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
      INFO: Pre-instantiating singletons in factory [org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans [entityManagerFactory,dataSource,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor,org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor,basicDAO,basicController,bug]; root of BeanFactory hierarchy]
      2006-12-23 16:33:08 org.hibernate.ejb.Version <clinit>

      For future reference but code snipplets within [C O D E] [/C O D E] blocks (without spaces). Makes it easier to read.
      Sorry for that, I'll remember now.

      Comment


      • #4
        I actually took your example classes and re-implemented this and it works without any problems. Don't see the same error that you are seeing. Can you post your complete application context files?

        Comment


        • #5
          Code:
          <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www.springframework.org/schema/beans"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xmlns:tx="http://www.springframework.org/schema/tx"
                 xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/tx
              http://www.springframework.org/schema/tx/spring-tx.xsd"
                 default-autowire="byName">
          
              <bean id="entityManagerFactory"
                    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
                  <property name="jpaVendorAdapter">
                      <bean
                              class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                          <property name="showSql" value="true" />
                          <property name="generateDdl" value="true" />
                          <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
          
                      </bean>
                  </property>
              </bean>
          
              <!-- DATA SOURCE -->
              <bean id="dataSource"
                    class="org.apache.commons.dbcp.BasicDataSource"
                    destroy-method="close">
                  <property name="driverClassName" value="com.mysql.jdbc.Driver" />
                  <property name="url" value="jdbc:mysql://localhost:4444/colere" />
                  <property name="username" value="root" />
                  <property name="password" value="whatever" />
              </bean>
          
              <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" />
          
              <tx:annotation-driven />
          
              <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
          
              <!-- my beans -->
              <bean id="basicDAO" class="colere.model.util.BasicDAO" />
              <bean id="basicController" class="colere.model.util.BasicController">
                  <property name="basicDAO" ref="basicDAO" />
              </bean>
              <bean id="bug" class="colere.model.test.BugThrower" >
                  <property name="basicController" ref="basicController"/>
              </bean>
          </beans>
          and my persistence.xml:
          Code:
          <?xml version="1.0" encoding="UTF-8"?>
          <persistence xmlns="http://java.sun.com/xml/ns/persistence"
                       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                       xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
                http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
                       version="1.0">
              <persistence-unit name="colere" transaction-type="RESOURCE_LOCAL">
                  <properties>
                     <property name="com.intellij.javaee.persistence.datasource" value="dataSource"/>
                      <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
                      <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
                  </properties>
              </persistence-unit>
          </persistence>

          Comment


          • #6
            Again, took your exact example and was unable to recreate the error. I did however need to tweak your configuration to get it to work. The LocalContainerEntityManagerFactoryBean requires that you specify a LoadTimeWeaver property.

            When debugging I'm seeing that BugThrower does have an instance variable that is a Proxy to the BasicController class.

            I'm using Spring 2.0.1, something must be different from what you are executing and what I am.

            Comment


            • #7
              Your property is expecting a BasicController (a concrete class) but since you are "<tx:annotation-driven />", it becomes a proxy, and a proxy isn't a concrete class, it implements an interface. I would recommend changing your BugThrower to use the BugController's interface (IBasicController) for the property. You can keep the property name itself the same.

              Code:
              package colere.model.test;
              import colere.model.util.*;
                public class BugThrower {
                  IBasicController basicController;
                  public IBasicController getBasicController() { 
                    return basicController; 
                  }
                  public void setBasicController(IBasicController basicController) {
                    this.basicController = basicController; 
                  }
              }

              Comment


              • #8
                Works! Thanks!
                So this is how Proxies are working

                One last question -- Why basicDAO injected into basicController works, even if I don't use an interface? Is there a rule telling me when I need an interface, apart from that it is a good OO practice to use them everywhere?

                Comment


                • #9
                  This is because the BasicDao is not being proxied. Just looked and when I was building your example I used the interface for the Controller (eclipse refactor support did this and I didn't realize it).

                  Only need an interface for the JDK Dynamic Proxies to work, so basically for anything you want to intercept on (Transactions, Security, etc....). But yes, it is a good practice to use interfaces between these layers anyway.

                  Comment


                  • #10
                    As Caleb said, anything that does become a proxy needs an interface or you need to use CGLIB proxies. These can be turned on via proxyTargetClass="true" (for normal proxies), or for the tx:annotation-driven proxy-target-class="true".

                    When using the @Transactional style of declarative transaction demarcation you can control whether or not interface- or class-based proxies are created via the presence and value of the "proxy-target-class" attribute on the <tx:annotation-driven/> element. If the value of the boolean-style value of the "proxy-target-class" attribute is set to "true", then class-based proxying will be in effect (and this currently requires the presence of the CGLIB library (cglib.jar) on the classpath). If the value of the "proxy-target-class" attribute is set to "false" or if the attribute is omitted, then standard JDK interface-based proxying will be in effect.
                    http://www.springframework.org/docs/...ve-annotations

                    Comment

                    Working...
                    X