2

We have a lot of DAO in project and their own implementations. For example, I have a class called CorDAO and CorDAOHibernate (CorDAO it's an interface and CorDAOHibernate implements CorDAO). For each interface I need do this:

    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
            <property name="dataSource" ref="dataSource"/>
            <property name="packagesToScan" value="com.myproject.*.to"/>
            <property name="hibernateProperties">
                <props>
                    <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                    <prop key="hibernate.hbm2ddl.auto">update</prop>
                    <prop key="hibernate.show_sql">false</prop>
                    <prop key="hibernate.cache.use_query_cache">true</prop>
                    <prop key="hibernate.cache.use_second_level_cache">true</prop>
                    <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
                </props>
            </property>
        </bean>

<bean id="genericDAO" class="com.myproject.dao.hibernate.GenericDAOHibernate">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

        <bean id="CorDAO" class="com.myproject.dao.hibernate.CorDAOHibernate">
                <property name="sessionFactory" ref="sessionFactory"/>
        </bean>
        <bean id="ExampleDAO" class="com.myproject.dao.hibernate.ExampleDAOHibernate">
                <property name="sessionFactory" ref="sessionFactory"/>
        </bean>

This it's why I wanna use ComponentScan in com.myproject.dao.hibernate.* package. Note that CorDAO it's a @Repository and CorDAOHibernate doesn't have any annotation. Every DAO class is a child of GenericDAO.

How can I use ComponentScan? I'm using Spring 3 so I tried this:

 <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="packagesToScan" value="com.myproject.*.to"/>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.cache.use_query_cache">true</prop>
                <prop key="hibernate.cache.use_second_level_cache">true</prop>
                <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
            </props>
        </property>
    </bean>

    <context:component-scan base-package="com.myproject.dao.hibernate" />

And I put a @Component annotation in CorDAOHibernate and GenericDAOHibernate but I got an IllegalArgumentException:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'corDAOHibernate' defined in URL [jar:file:/home/danielamorais/Documents/apache-tomcat-8.0.47/webapps/myproject/WEB-INF/lib/myproject-3.1.0.jar!/com/myproject/dao/hibernate/corDAOHibernate.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: 'sessionFactory' or 'hibernateTemplate' is required

I think this happens because sessionFactory it's autowired in GenericDAOHibernate but is null in CorDAOHibernate. How can I fix this with component scan?

Classes CorDAO

@Repository
public interface CorDAO extends GenericDAO {
    //Methods
}

CorDAOHibernate

@Component
public class CorDAOHibernate extends GenericDAOHibernate implements CorDAO {
    //Methods
}

GenericDAO

public interface GenericDAO extends DAO {
    //Methods. This class doesn't contains @Repository annotation
}

GenericDAOHibernate

    @Component
    public class GenericDAOHibernate extends HibernateDaoSupport implements GenericDAO, PropertySelector {

        @Autowired
        private SessionFactory sessionFactory;

    protected Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }
        //Methods
    }

DAO

public interface DAO {
//There's no method here.
}

Also, adding @Component("genericDAO") I got (probably because an inheritance problem):

NoUniqueBeanDefinitionException: No qualifying bean of type [com.myproject.dao.GenericDAO] is defined: expected single matching bean but found 88

Daniela Morais
  • 2,125
  • 7
  • 28
  • 49
  • 1
    Could you post an example of CorDAOHibernate? – Sergey Prokofiev Feb 16 '18 at 16:20
  • Thanks, so you need to get rid of sessionFactory field in your GenericDAOHibernate class. It extends HibernateDaoSupport which is already has [setSessionFactory for you](https://docs.spring.io/spring/docs/4.3.13.RELEASE/javadoc-api/org/springframework/orm/hibernate4/support/HibernateDaoSupport.html#setSessionFactory-org.hibernate.SessionFactory-) – Sergey Prokofiev Feb 16 '18 at 16:40
  • Do child classes have access to the **private** SessionFactory sessionFactory field? If so, please add how it implemented. If concrete class like `GenericDAOHibernate` has no access to this fiels it could be a problem – ADS Feb 16 '18 at 16:41
  • What is the constructor of `CorDAOHibernate`? (You know, that a `@Bean/@Component/etc`requires a zero argument or autowired constructor!?) – xerx593 Jan 18 '19 at 12:17
  • And the second error message is very strange: You defined 88 `GenericDao` "beans"!? – xerx593 Jan 18 '19 at 12:23

3 Answers3

1

Well, your main problem is because of this :

Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: 'sessionFactory' or 'hibernateTemplate' is required

which I also answered a similar question before.

To make a long story short , your GenericDAOHibernate is implemented in a wrong way :

  1. No need to have SessionFactory internally as HibernateDaoSupport already implemented for you which you can get from calling getSessionFactory()
  2. You have to pass the SessionFactory to HibernateDaoSupport through constructor in order to initialise HibernateTemplate in HibernateDaoSupport. Otherwise , it will be null and hence this exception message happens.

Also , your @Repository and @Component also seem to be annotated awkward. Basically, I would only use @Repository for DAO .It is the same as @Component plus the spring "exception translation" feature.

Anyway, please try to change to the followings:

@Repository  
public class GenericDAOHibernate extends HibernateDaoSupport implements GenericDAO, PropertySelector {

         @Autowired
         public GenericDAOHibernate(SessionFactory sessionFactory){
             super.setSessionFactory(sessionFactory);
         }

        protected Session getCurrentSession() {
            return getSessionFactory().getCurrentSession();
        }

}     

And each DAO implementation :

@Repository
public class CorDAOHibernate extends GenericDAOHibernate implements CorDAO {
     public CorDAOHibernate(SessionFactory sessionFactory) {
          super(sessionFactory);
     }
}   

Also , remove that @Repository from CorDAO interface and that @Component("genericDAO") stuff.....

Ken Chan
  • 84,777
  • 26
  • 143
  • 172
0

You have to annotate class declared as sessionFactory as @Bean (or @Component, see this question and make sure it will be scanned via ComponentScan.

Also consider to use Repository approach from Spring Data as way where you don't have to write boilerplate code.

ADS
  • 708
  • 3
  • 14
0

I think you should remove

@Autowired private SessionFactory sessionFactory;

field.

Because sessionFactory field is already define in parent class. And setSessionFactory method decleared as final. So you don't need to decleare new private field for sessionFactory.

Here is setSessionFactory method implementation.

/**
 * Set the Hibernate SessionFactory to be used by this DAO.
 * Will automatically create a HibernateTemplate for the given SessionFactory.
 * @see #createHibernateTemplate
 * @see #setHibernateTemplate
 */
public final void setSessionFactory(SessionFactory sessionFactory) {
    if (this.hibernateTemplate == null || sessionFactory != this.hibernateTemplate.getSessionFactory()) {
        this.hibernateTemplate = createHibernateTemplate(sessionFactory);
    }
}

Remove both sessionFactory and getCurrentSession(HibernateDaoSupport already have currentSession() method)

or change getCurrentSession as follows

public class GenericDAOHibernate extends HibernateDaoSupport implements GenericDAO, PropertySelector {



protected Session getCurrentSession()  throws DataAccessResourceFailureException  {
    return currentSession()
}
    //Methods
}
mfe
  • 1,158
  • 10
  • 15