Search code examples
javaspringentitymanager

How can I specify which entity manager factory to use, without modifying the DAO class?


I have a Java 7 / Spring 3.2.17 application which has to connect to two different databases, so I have two different persistence.xml files, each one declaring its own persistence unit.

In my application context I have defined two entity manager factories, such as:

<bean id="emf1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="myDatasource1" />
    <property name="persistenceXmlLocation" value="classpath:META-INF/persistence1.xml" />
    <property name="persistenceUnitName" value="pu1" />
    ...
</bean>

And in my DAO classes I just let Spring inject the entity manager:

@PersistenceContext
private EntityManager entityManager;

public void setEntityManager (...) { ... }

Spring complains that I have two EM factories so it doesn't know which one to use:

NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: emf1,emf2

I have partially solved it by specifying which persistence unit I want to use, like this:

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

public void setEntityManager (...) { ... }

That solved the problem for the classes connecting to the first database. My problem is that the classes for the other DB are part of a third-party library, so I can't modify them to add the unitName attribute. Is there any other way I can do it?


I have tried a few options, but all of them lead to the same error message:

  1. Extending the class so I can "override the annotation":
public class MyDao extends TheDaoThatICannotModify {
    @Override
    @PersistenceContext(unitName = "pu2")
    public void setEntityManager (EntityManager em) {
        super.setEntityManager(em);
    }
}
  1. Instantiating the EM and injecting it myself:
<bean id="entityManager2" factory-bean="emf2" factory-method="getObject" />

<bean id="myDao" class="com.foo.TheDaoThatICannotModify">
    <property name="entityManager" ref="entityManager2" />
</bean>
  1. Adding the primary="true" attribute to my emf2 bean (and primary="false" to emf1).

  2. Adding the autowire-candidate="false" attribute to my emf1 bean.


Solution

  • I got it working... by using Spring injection only with my own classes, and passing the EM to the evil DAOs myself:

    public class MyDaoSingletonFactoryIsh {
        @PersistenceContext(unitName = "pu2")
        private EntityManager em; // Injected by Spring
    
        private static TheDaoThatICannotModify dao = null;
    
        public TheDaoThatICannotModify getDAO() {
            if (dao == null) {
                dao = new TheDaoThatICannotModify();
                dao.setEntityManager(em);
            }
            return dao;
        }
    }
    

    I don't know how to call this pattern: factory, singleton, wrapper? It doesn't really fit in any of these categories, it's a weird combination of them. Which isn't probably a good sign, it looks like a huge code smell and I'd prefer to avoid it. But at least it's working, so, lacking of a better solution...