Announcement Announcement Module
Collapse
No announcement yet.
Spring Data Rest and multiple EntityManagers Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring Data Rest and multiple EntityManagers

    Hi, I'm trying to setup two different persistence units with independent models. I've just get to work everything except Spring Data Rest. When tomcat starts it throws:

    Code:
    org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [javax.persistence.EntityManagerFactory] is defined: expected single bean but found 2
    	at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findDefaultEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:537)
    	at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:496)
    	at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.resolveEntityManager(PersistenceAnnotationBeanPostProcessor.java:657)
    	at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.getResourceToInject(PersistenceAnnotationBeanPostProcessor.java:630)
    	at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:159)
    	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
    	at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:339)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1106)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
    ...
    Doing some debugging I've found that in org.springframework.orm.jpa.support.PersistenceAnn otationBeanPostProcessor checks that only one EntityManagerFactory is present:

    Code:
    protected EntityManagerFactory findDefaultEntityManagerFactory(String requestingBeanName)
    			throws NoSuchBeanDefinitionException{
    
    		String[] beanNames =
    				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, EntityManagerFactory.class);
    		if (beanNames.length == 1) {
    			String unitName = beanNames[0];
    			EntityManagerFactory emf = (EntityManagerFactory) this.beanFactory.getBean(unitName);
    			if (this.beanFactory instanceof ConfigurableBeanFactory) {
    				((ConfigurableBeanFactory) this.beanFactory).registerDependentBean(unitName, requestingBeanName);
    			}
    			return emf;
    		}
    		else {
    			throw new NoSuchBeanDefinitionException(
    					EntityManagerFactory.class, "expected single bean but found " + beanNames.length);
    		}
    	}
    Is there any way to tell Spring Data Rest which EntityManager should be used?

    My spring configuration is:

    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:context="http://www.springframework.org/schema/context"
    	xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    	xmlns:repository="http://www.springframework.org/schema/data/repository"
    	xsi:schemaLocation="http://www.springframework.org/schema/data/repository http://www.springframework.org/schema/data/repository/spring-repository-1.4.xsd
    		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    		http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
    		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
    
    	<context:annotation-config />
    
    	<bean id="dataSourceGeneral" class="org.springframework.jndi.JndiObjectFactoryBean">
    		<property name="jndiName" value="java:comp/env/jdbc/GeneralPOS" />
    	</bean>
    
    	<bean id="entityManagerGeneral"
    		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    		<property name="persistenceUnitName" value="generalPU"></property>
    		<property name="dataSource" ref="dataSourceGeneral"></property>
    		<property name="packagesToScan" value="es.infinitel.pos.domain.general"></property>
    		<property name="jpaVendorAdapter">
    			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    				<property name="showSql" value="true"></property>
    				<property name="generateDdl" value="true"></property>
    				<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect"></property>
    			</bean>
    		</property>
    		<property name="jpaProperties">
    			<props>
    				<prop key="hibernate.ejb.entitymanager_factory_name">
    					entityManagerGeneral
    				</prop>
    			</props>
    		</property>
    	</bean>
    
    	<bean id="dataSourceRestUser" class="org.springframework.jndi.JndiObjectFactoryBean">
    		<property name="jndiName" value="java:comp/env/jdbc/UserPOS" />
    	</bean>
    
    	<bean id="dataSourceClientes" class="es.infinitel.pos.backend.ClienteRoutingDataSource">
    		<property name="targetDataSources">
    			<map key-type="java.lang.String">
    				<entry key="restuser" value-ref="dataSourceRestUser"></entry>
    			</map>
    		</property>
    	</bean>
    
    	<bean id="entityManagerUser"
    		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    		<property name="persistenceUnitName" value="userPU"></property>
    		<property name="dataSource" ref="dataSourceClientes"></property>
    		<property name="packagesToScan" value="es.infinitel.pos.domain.cliente"></property>
    		<property name="jpaVendorAdapter">
    			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    				<property name="showSql" value="true"></property>
    				<property name="generateDdl" value="true"></property>
    				<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect"></property>
    			</bean>
    		</property>
    		<property name="jpaProperties">
    			<props>
    				<prop key="hibernate.ejb.entitymanager_factory_name">
    					entityManagerUser
    				</prop>
    			</props>
    		</property>
    	</bean>
    	
    	<bean id="transactionManagerUser" class="org.springframework.orm.jpa.JpaTransactionManager">
    		<property name="entityManagerFactory" ref="entityManagerUser" />
    	</bean>
    
    	<bean id="transactionManagerGeneral" class="org.springframework.orm.jpa.JpaTransactionManager">
    		<property name="entityManagerFactory" ref="entityManagerGeneral" />
    	</bean>
    
    	<jpa:repositories base-package="es.infinitel.pos.repositories.cliente"
    		entity-manager-factory-ref="entityManagerUser" >
    		<repository:include-filter type="assignable" expression="es.infinitel.pos.repositories.cliente.IdentidadRepository"/>
    	</jpa:repositories>
    	
    		<jpa:repositories base-package="es.infinitel.pos.repositories.general"
    		entity-manager-factory-ref="entityManagerUser" >
    		<repository:exclude-filter type="assignable" expression="es.infinitel.pos.repositories.cliente.IdentidadRepository"/>
    	</jpa:repositories>
    	
    	
    	<bean id="dummy" class="es.infinitel.pos.backend.Dummy"></bean>
    
    </beans>
    Thanks for your help.
    Pepe Ribas
    Last edited by Infinitel; Oct 29th, 2012, 06:30 AM.

  • #2
    If you already looked at the sources I suggest you take a look again...

    In short explicitly configure the PersistenceAnnotationBeanPostProcessor and tell it which EMF to use as the default (in case you don't specify a unit name).

    Comment


    • #3
      Originally posted by Marten Deinum View Post
      If you already looked at the sources I suggest you take a look again...

      In short explicitly configure the PersistenceAnnotationBeanPostProcessor and tell it which EMF to use as the default (in case you don't specify a unit name).
      I've been debugging the error, and readed what you told me, but the problems seems to be populating the Spring Data Rest bean "jpaRepositoryExporter". That bean has a "entityManager" property which is the one that produces the error.

      The Spring Data Jpa works well with these multiple EntitiyManagerFactory's settings, only when adding the Rest functionality fails.

      I don't know how to make it work. In Spring Data Jpa I've set the entity-manager-factory-ref for each jpa:repository definition but I can not find where to set it for Spring Data Rest.

      I figured that those setting were taken from the Spring Data Jpa settings but when debugging i see that the persistence unit value attached to jpaRepositoryExporter bean is set as an empty string. When the PersistenceAnnotationBeanPostProcessor tries to setup the entityManager for jpaRepositoryExporter receives that empty string as the persistence unit so even if i set the PersistenceAnnotationBeanPostProcessor available persistenceUnits the bean instantiation fails and tries to look for the default EntityManagerFactory and finds 2 of them.

      Comment


      • #4
        Needless to say that I want to publish both persistence units as Rest services. So setting a default EMF is not what I'm looking for.

        Comment


        • #5
          Haven't worked with multiple units and Spring Data Rest so it is hard to say. I would simply create 2 servlets which both have a different default persistence unit configured, kind of a work around. Next to that I suggest registering a JIRA issue.

          Comment


          • #6
            It's already reported at Jira:

            https://jira.springsource.org/browse/DATAREST-52

            Thanks for your help anyway.

            Comment

            Working...
            X