Spring Java Configuration No bean named ‘entityManagerFactory’ is defined

configurationentitymanagerspringspring-dataspring-data-jpa

I spent a day trying to figure it out and eventually had to turn to stackoverflow for some expert advise.

I am setting up spring configuration using java to have two datasources and two LocalContainerEntityManagerFactoryBean as below. But Spring by default seems to look for entityManagerFactory() and throwing exception (included stacktrace below). How can I configure spring to use my entitymanagerfactories instead of default name.

@Bean(name="visionDataSource")
public DataSource visionDataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    // set properties..
    return dataSource;
}

@Bean(name="stormDataSource")
public DataSource visionDataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    // set properties..
    return dataSource;
}

  @Bean(name="visionentityManagerFactory")
public LocalContainerEntityManagerFactoryBean visionentityManagerFactory() {
    LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
    entityManagerFactoryBean.setDataSource(visionDataSource());
    //entityManagerFactoryBean.setPersistenceUnitManager(persistenceUnitManager());
    //entityManagerFactoryBean.setPersistenceXmlLocation(null);
    entityManagerFactoryBean.setPersistenceUnitName("visionEntityManagerFactory");
    entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistence.class);
    entityManagerFactoryBean.setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
    entityManagerFactoryBean.setJpaProperties(hibProperties());
    entityManagerFactoryBean.afterPropertiesSet();
    System.out.println("*********************visionEntityManagerFactory********************");
    return entityManagerFactoryBean;
}

 @Bean(name="stormEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean stormEntityManagerFactory() {
    entityManagerFactoryBean.setDataSource(stormDataSource());
    // set other properties
    return entityManagerFactoryBean;
  }

Error LOG:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#1': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' is defined
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:329)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:107)
at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:616)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:441)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1015)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:911)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:271)
… 51 more

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:549)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1095)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:277)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:323)
… 59 more

Update: I am using JPARepository

  public interface ContactRepository extends JpaRepository<Contact, Serializable> {
    List<Contact> findByCompanyId(int companyId);
  }

I already tried to extend a custom repository injecting entitymanager like below. But this did not help either.

  public interface ContactRepository extends DefaultRepository<Contact, Serializable> {
    List<Contact> findByCompanyId(int companyId);
   }

@NoRepositoryBean
public class DefaultRepositoryImpl<T, ID extends Serializable> extends SmpleJpaRepository<T, ID> implements 
                        DefaultRepository<T,ID> {

@PersistenceContext(unitName="visionEntityManagerFactory")
private EntityManager entityManager;

/**
 * @param domainClass
 * @param em
 */
 public DefaultRepositoryImpl(Class<T> domainClass, EntityManager em) {
 super(domainClass, em);
 }

 /**
  * {@inheritDoc}
  */
 protected Object getTargetRepository(RepositoryMetadata metadata) {
     return new DefaultRepositoryImpl<T, ID>((Class<T>) metadata.getDomainType(), entityManager);
 }
 /**
  * {@inheritDoc}
  */
 protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
     return DefaultRepository.class;
     }
  }

Best Answer

One possible solution.

public class MyRepositoryImpl extends JdbcDaoSupport implements MyRepository {

    @Qualifier("odsDataSource")
    @Autowired(required = true)
    private DataSource ds;

    public MyRepositoryImpl() {
    }

    @PostConstruct
    void postConstruct() {
        setDataSource(ds);
    }

    ...
}

If you develop your repositories by extending JdbcDaoSupport (and also a few other Spring-provided helpers), then they will default to attempting to wire by name on the default "entityManagerFactory". So you need to initialise them by injecting your alternatively-named data beans.

Another possibility assuming you are using JPA.

@Repository
public class MyRepositoryImpl implements MyRepository {
    @PersistenceContext(unitName="MyPersistenceUnit")
    private EntityManager entityManager;

    public List<MyModel> findAll() {
        return entityManager.createNamedQuery("MyModel.findAll").getResultList();
    }
}

Update: For folks coming across this issue more recently, using Spring Boot and Spring Data JPA, I wrote a blog post running through the essentials of getting that working: http://scattercode.co.uk/2016/01/05/multiple-databases-with-spring-boot-and-spring-data-jpa/