[RESOLVIDO] Spring + JPA injetando o entityManagerFactory

28 respostas
cris.t

Olá pessoal, estou tentando utilizar o Spring com o JPA, porém não estou conseguindo fazer a injeção de dependencia do entityManagerFactory, estou urilizando uma aplicação web, será que alguem pode me ajudar?

jps-servlet.xml
<?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:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
	
	
	<bean name="/hello.htm" class="orm.controller.Teste" />
	
	<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>
        <property name="prefix" value="/WEB-INF/jsp/"></property>
        <property name="suffix" value=".jsp"></property>        
    </bean>
    	
	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>

	<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="loadTimeWeaver">
			<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
		</property>
	</bean>
	
	<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
</beans>
web.xml
<servlet>
    <servlet-name>jpa</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>jpa</servlet-name>
    <url-pattern>*.htm</url-pattern>
  </servlet-mapping>
  
  <context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>
		/WEB-INF/jpa-servlet.xml
	</param-value>
  </context-param>
classe Product
@Entity
public class Product {

	private int id;
	private String name;
	
	public Product() {
	}
	
	@SequenceGenerator(name = "generator", sequenceName = "seq_product", allocationSize = 1)
	@Id
	@GeneratedValue(strategy = SEQUENCE, generator = "generator")
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}
ProductDAO
@PersistenceContext
public class ProductDAO {
		
	@PersistenceUnit
	private EntityManagerFactory _entityManagerFactory = null;
	private EntityManager _entityManager = null;

	public ProductDAO() {
		_entityManager = _entityManagerFactory.createEntityManager();
	}

	public void insert(Product product) {
		_entityManager.getTransaction().begin();
		_entityManager.persist(product);
		_entityManager.getTransaction().commit();
	}
	
	public void delete(Product product) {
		_entityManager.getTransaction().begin();
		_entityManager.remove(product);
		_entityManager.getTransaction().commit();
	}
	
	public void update(Product product) {
		_entityManager.getTransaction().begin();
		_entityManager.merge(product);
		_entityManager.getTransaction().commit();
	}
	
	public Product findByPK(Object obj) {
		return _entityManager.find(Product.class, obj);
	}
	
	public ArrayList<Product> findAll() {
		Query query = _entityManager.createQuery("from Product" );
		
		return (ArrayList<Product>) query.getResultList();
	}

	public EntityManagerFactory get_entityManagerFactory() {
		return _entityManagerFactory;
	}

	public void set_entityManagerFactory(EntityManagerFactory managerFactory) {
		_entityManagerFactory = managerFactory;
	}

	public EntityManager get_entityManager() {
		return _entityManager;
	}

	public void set_entityManager(EntityManager manager) {
		_entityManager = manager;
	}
}
persistence.xml
<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="maindatabase" transaction-type="RESOURCE_LOCAL">
		<provider>org.hibernate.ejb.HibernatePersistence</provider> 
		<properties>
			<property name="hibernate.connection.driver_class" value="org.postgresql.Driver" /> 
			<property name="hibernate.connection.username" value="postgres" /> 
			<property name="hibernate.connection.password" value="database" /> 
			<property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/exemplo" /> 
			<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" /> 
			<property name="hibernate.show_sql" value="true" /> 
		</properties>
	</persistence-unit>
</persistence>
classe Teste
public class Teste implements Controller{

	protected final Log logger = LogFactory.getLog(getClass());

	@Override
	public ModelAndView handleRequest(HttpServletRequest arg0,
			HttpServletResponse arg1) throws Exception {
		
		
		ProductDAO productDAO = new ProductDAO();
		
		Product product = new Product();
		product.setName("Teste");
		
		productDAO.insert(product);
		
        String now = (new Date()).toString();
        logger.info("Returning hello view with " + now);

        return new ModelAndView("hello", "now", now);

	}
}

28 Respostas

cris.t

Pessoal quando eu o chamo pelo metodo main a dependencia é feita normalmente, funciona bunitinho:

public static void main(String[] args) {
		
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("jpa-servlet.xml");  
		
		ProductDAO productDAO =(ProductDAO) applicationContext.getBean("productDAO");
		
		Product product = new Product();
		product.setName("Teste");
		
		productDAO.insert(product);
		
	}

Não consigo fazer a dependencia fodando pelo servidor, alguem ai pode me ajudar?

Guilherme_Gomes

O Spring é um framework poderoso. Você realmente precisa injetar o EntityManagerFactory nos seus beans?

Você já ouviu falar no conceito “Open Session/EntityManager in View”?
O Spring pode fazer isso por você: org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter

<filter>
		<filter-name>inviewr</filter-name>
		<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
	</filter>
	
	<filter-mapping>
		<filter-name>inview</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

Depois você poderia usar apenas os seus DAOs assim:

@PersistenceContext
	private EntityManager entityManager;

E colocar a Annotation @Transactional nos métodos que dependem de uma transação (se não souber o suficiente sobre transactions no Spring, da uma olhada na net).

@Transactional
	public void delete(EntityClass entity) {
		entityManager.remove(entity);
	}

Outra coisa, existe uma GRANDE diferença entre isso:

ProductDAO productDAO =(ProductDAO) applicationContext.getBean("productDAO");

e isso

ProductDAO productDAO = new ProductDAO();
cris.t

Olá Guilherme, estou iniciando no spring agora, então não tenho experiência com este framework, preciso fazer a integração do Spring com JPA, estou me baseando nesta parte da documentação http://static.springframework.org/spring/docs/2.0.x/reference/orm.html e em alguns pequenos tutoriais que vi na net, porem nao vi nenhum exemplo completo e pouca coisa falando de JPA puro com Spring.

Como já te disse tenho pouco conhecimento do Spring, até agora tinha entendido que ele funciona desta maneira, gerenciando as dependências através dos beans, não sabia que teria outra forma além desta.

Não tenho o conhecimento deste conceito, e como devo utilizar além de mapear os filtros no web.xml? Ele vai criar o EntityManagerFactory Automaticamente, vai ser necessários o mesmo mapeamento nos beans?

Quando comecei a estudar Spring fiz exempos utilizando aplicações desktop e utilizei a primiera forma pra fazer as injeções de dependência necessárias, agora que comecei a utilizar a parte web vi que isso é feito de forma diferente.

Desde já agradeço a atenção Guilherme.

cris.t

Tentei implementar mas ocorreu a seguinte exception:

java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.apache.tomcat.util.IntrospectionUtils.callMethod1(IntrospectionUtils.java:922)
	at org.apache.tomcat.util.digester.SetNextRule.end(SetNextRule.java:193)
	at org.apache.tomcat.util.digester.Rule.end(Rule.java:229)
	at org.apache.tomcat.util.digester.Digester.endElement(Digester.java:1140)
        ....
        ....
        ....
Caused by: java.lang.IllegalArgumentException: Filter mapping specifies an unknown filter name inview
	at org.apache.catalina.core.StandardContext.addFilterMap(StandardContext.java:2160)
	... 37 more
04/05/2009 10:41:08 org.apache.catalina.startup.ContextConfig applicationWebConfig
SEVERE: Parse error in application web.xml file at jndi:/localhost/jpa/WEB-INF/web.xml
java.lang.IllegalArgumentException: Filter mapping specifies an unknown filter name inview
	at org.apache.tomcat.util.digester.Digester.createSAXException(Digester.java:2808)
	at org.apache.tomcat.util.digester.Digester.createSAXException(Digester.java:2834)
	at org.apache.tomcat.util.digester.Digester.endElement(Digester.java:1143)
	at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:601)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(XMLDocumentFragmentScannerImpl.java:1774)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2930)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:648)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:807)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
	at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:107)
        ....
        ....
        ....
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
	at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
04/05/2009 10:41:08 org.apache.catalina.startup.ContextConfig applicationWebConfig
SEVERE: Occurred at line 31 column 20
Guilherme_Gomes

Você disse uma coisa muito importante, o Spring faz Injeção de Dependencias. Mas como ele pode fazer uma injeção de dependencia com você fazendo ProductDAO dao = new ProductDAO()?

Você deve chamar o Spring para pegar o DAO.

Usando o web.xml para declarar o XML do Spring, no meu caso é o seguinte:

<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring-config.xml, /WEB-INF/spring-security.xml, /WEB-INF/spring-core.xml
        </param-value>
    </context-param>

E nesses XMLs você declara as suas classes e suas dependencias (ou usa as annotations). Assim, quando algum Bean for acessado, a injeção de dependencia será automatica.

Agora, se estiver acessando seus beans via uma servlet você terá um problema, pois servlets são criadas pelo ServletContainer (Tomcat, Jetty, …). O jeito mais facil de acessar um bean via servlet é fazendo o seguinte:

ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
ProductDAO dao = (ProductDAO) context.getBean("ProductDAO ");

Existe uma servlet do spring que da forwarding pra sua servlet e todo um esquema que eu num gostei muito e não lembro mais como faz ^^
Se quiser, pode dar uma pesquisada por isso.

cris.t

Então Guilherme, como estou fazendo apenas um exemplo primeiro, estou usando apenas o arquivo spring-servlet.xml que pelo que eu vi é default, é o que ele vai procurar caso nao seja especificado nenhum no context-param, correto?

Neste arquivo como eu ja postei acima eu declarei a minha DAO e o entityManagerFactory e também estou declarando a minha pagina que vai chamar a minha classe de “controle” onde eu chamo a DAO. É neste ponto que não estou conseguindo fazer a implementação acho que não é desta maneira que devo fazer, não sei se consegui expressar meu problema, mas ai qdo eu chamo a DAO da um NullPointer pois, a injeção não é feita, na minha coloquei as Annotation na DAO @PersistenceUnit no entityManagerFactory e @PersistenceContext em cima da declaração da minha classe, desta maneira qdo eu chama a aplicação como se fosse uma aplicação desktop, pelo método main funciona, mas qdo eu rodo com o Tomcat, pelo server a injeção não é feita.

Guilherme_Gomes

Vou mostrar alguns trechos importantes de um código que tenho aqui:

Meu dao:

@PersistenceContext
	private EntityManager entityManager;

web.xml

<filter>
		<filter-name>transactionFilter</filter-name>
		<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
	</filter>
	
	<filter-mapping>
		<filter-name>transactionFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

//...

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring-config.xml, /WEB-INF/spring-security.xml, /WEB-INF/spring-core.xml
        </param-value>
    </context-param>
    
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

    <listener>
        <listener-class>
            org.springframework.web.context.request.RequestContextListener
        </listener-class>
    </listener>

arquivos de configuração do spring:

<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />
	<context:component-scan base-package="br.com......." />

	<bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver" />
		<property name="jdbcUrl" value="URL" />
		<property name="user" value="LOGIN" />
		<property name="password" value="SENHA/>
	</bean>

	<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
        <property name="dataSource" ref="myDataSource" />
    </bean>

	<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
        <property name="dataSource" ref="myDataSource" />
    </bean>

	<bean id="entityManagerFactory"
          class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="myDataSource" />
        <!-- <property name="persistenceUnitName" value="nweb4"></property> -->
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.format_sql">false</prop>
            </props>
        </property>
        <property name="persistenceProvider">
        	<bean class="br.com.........interceptor.ConfigurableHibernatePersistence"> MEU PERSISTENTE PROVIDER
        		<property name="interceptor">
        			<bean class="br.com.......interceptor.LogInterceptor" />
        		</property>
        		<property name="postInsertEventListener" ref="logSaveOperation"></property>
        	</bean>
        </property>
    </bean>

No contexto WEB, você deve informar o Listener que inicia o ApplicationContext do Spring.
Não esqueça das coisas que ja postei…

cris.t

no meu caso estou utilizando o persistence.xml para configuração do dataSource, mesmo assim eu preciso declarar de novo na configuração do Spring como vc fez? E este property chamado persistenceProvider pra que que serve? :slight_smile:

Guilherme_Gomes

O arquivo persistence.xml é obrigatório, JPA exige que ele exista na pasta META-INF na raiz do classpath, no caso, o meu esta assim:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" 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">
    <persistence-unit name="***" transaction-type="RESOURCE_LOCAL">
    	<!--provider>br.com.****.interceptor.ConfigurableHibernatePersistence</provider>
    	<provider>org.hibernate.ejb.HibernatePersistence</provider-->
    </persistence-unit>
</persistence>

Você não precisa declarar as propriedades no arquivo do spring caso esteja usando o persistence.xml. No meu caso, preferi declarar tudo no spring por uma questão de centralização de informações referentes ao banco.

Mas, mesmo que você utilize o persistence.xml, você precisa declarar a entityManagerFacory como o código que postei.

Quanto ao PersistenceProvider que postei, é uma solução que eu encontrei na internet para conseguir usar o Provider do Hibernate e ainda assim usar um interceptor com ele, injetado pelo Spring, com o provider padrão do hibernate não dá, tem que inserir via propriedades…

cris.t

Fiz as configurações e alterações, apareceu a seguinte exception:
Será que é algum jar faltando?

SEVERE: Context initialization failed
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/jpa-servlet.xml]; nested exception is java.lang.NoSuchMethodError: org.springframework.aop.config.AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(Lorg/springframework/beans/factory/xml/ParserContext;Lorg/w3c/dom/Element;)V
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:420)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:342)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:310)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:143)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:178)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:149)
	at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:124)
	at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:92)
	at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:123)

...


Caused by: java.lang.NoSuchMethodError: org.springframework.aop.config.AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(Lorg/springframework/beans/factory/xml/ParserContext;Lorg/w3c/dom/Element;)V
	at org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser$AopAutoProxyConfigurer.configureAutoProxyCreator(AnnotationDrivenBeanDefinitionParser.java:109)
	at org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser.parse(AnnotationDrivenBeanDefinitionParser.java:80)
	at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:69)


...


04/05/2009 14:19:41 org.apache.catalina.core.StandardContext listenerStart
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/jpa-servlet.xml]; nested exception is java.lang.NoSuchMethodError: org.springframework.aop.config.AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(Lorg/springframework/beans/factory/xml/ParserContext;Lorg/w3c/dom/Element;)V
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:420)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:342)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:310)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:143)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:178)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:149)
	at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:124)
	at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:92)
	at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:123)


...

Caused by: java.lang.NoSuchMethodError: org.springframework.aop.config.AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(Lorg/springframework/beans/factory/xml/ParserContext;Lorg/w3c/dom/Element;)V
	at org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser$AopAutoProxyConfigurer.configureAutoProxyCreator(AnnotationDrivenBeanDefinitionParser.java:109)
	at org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser.parse(AnnotationDrivenBeanDefinitionParser.java:80)
Guilherme_Gomes

Isso cheira a incompatibilidade. Algo na sua aplicação está com dependencia errada, por exemplo:

framework1-2.0.jar depende de framework2-3.2.jar
mas o que você tem é o framework2-2.7.jar

A incompatibilidade está no spring-aop aparentemente:

org.springframework.aop.config.AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(…);

Ele está procurando pelo metodo registerAutoProxyCreatorIfNecessary na classe AopNamespaceUtils, pois alguem esta chamando, mas não existe. Problema de incompatibilidade de versões.

cris.t

Olá Guilherme consegui resolver a exception que postei e outras que vieram depois… agora ta dando essa que não estou conseguindo entender, parece que estou injetando o entityManagerFacoty no EntityManager, mas acho que não estou fazendo isso eu fiz o código da maneira que vc postou.

EVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
java.lang.IllegalStateException: Specified field type [interface javax.persistence.EntityManagerFactory] is incompatible with resource type [javax.persistence.EntityManager]
	at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.checkResourceType(InjectionMetadata.java:159)
	at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.&lt;init&gt;(PersistenceAnnotationBeanPostProcessor.java:560)
	at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$1.doWith(PersistenceAnnotationBeanPostProcessor.java:359)
	at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:523)
	at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:500)
	at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findPersistenceMetadata(PersistenceAnnotationBeanPostProcessor.java:351)
	at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessMergedBeanDefinition(PersistenceAnnotationBeanPostProcessor.java:296)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors(AbstractAutowireCapableBeanFactory.java:745)

código da DAO

public class ProductDAO {
		
	private EntityManager _entityManager = null;
	
	@PersistenceContext
	private EntityManagerFactory _entityManagerFactory = null;
	
	
	public ProductDAO() {
	}
	
	@Transactional
	public void insert(Product product) {
		_entityManager = _entityManagerFactory.createEntityManager();
		_entityManager.getTransaction().begin();
		_entityManager.persist(product);
		_entityManager.getTransaction().commit();
	}

        // getters and setters
Guilherme_Gomes

A annotation PersistenceContext vai no EntityManager e o próprio Spring injeta um EntityManager para você, esse é o erro. Ele está tentando injetar um entitymanager em um entitymanagerfactory.

cris.t

Então ele já cria o entityManager pra mim automático, eu digo essa linha?:

_entityManager = _entityManagerFactory.createEntityManager();

pois agora aquele erro acabou mas tanto entityManager como o EntityManagerFactory estão dando NullPointerException

java.lang.NullPointerException
	at orm.dataaccess.dao.ProductDAO.insert(ProductDAO.java:28)
	at orm.controller.Teste.handleRequest(Teste.java:34)
	at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
Guilherme_Gomes

Faz assim, arranca esse EntityManagerFactory do seu codigo, deixa só o EntityManager, ele já vai vir com um instancia setada pelo Spring.

cris.t

é tirei, mas o NullPointer continua, parece que ele nao fez a injeção.

SEVERE: Servlet.service() for servlet jpa threw exception
java.lang.NullPointerException
	at orm.dataaccess.dao.ProductDAO.insert(ProductDAO.java:24)
	at orm.controller.Teste.handleRequest(Teste.java:34)
	at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)

ProductDAO

public class ProductDAO {
	
	@PersistenceContext
	private EntityManager _entityManager = null;
	
	public ProductDAO() {
	}
	
	@Transactional
	public void insert(Product product) {
		_entityManager.getTransaction().begin();
		_entityManager.persist(product);
		_entityManager.getTransaction().commit();
	}

	public EntityManager getEntityManager() {
		return _entityManager;
	}

	public void setEntityManager(EntityManager entityManager) {
		_entityManager = entityManager;
	}
cris.t

Estava dando uma pesquisada e vi essa parte da documentação falando de algumas configurações no Tomcat, será que isso pode influenciar?
http://static.springframework.org/spring/docs/2.5.x/reference/orm.html

Guilherme_Gomes

Creio que o problema seja que você chamou seu EntityManager de _entityManager, então ele procura o setter set_entityManager() ou algo do tipo, tente mudar o nome da variavel apenas para entityManager e ele vai procurar pelo setEntityManager().

cris.t

Eu configurei no eclipse que todos os atributos teriam underline, entao acho que quando ele encontra os metodos getters ou setters ele o desconsidera. Porém tirei pra ver e mesmo assim nao foi injetado. Ta bem complicado :frowning:

Guilherme_Gomes

Revendo, você seguiu esses itens:

  1. Configurou o Spring e os seus beans?
  2. Colocou o OpenEntityManagerInViewFilter no web.xml?
  3. Colocou @PersistenceContext nos EntityManagers?
  4. Os DAOs que devem receber o PersistenceContext estão sendo criados pelo Spring e não por um new Object()?
  5. Sua aplicação possui os Listeners do Spring necessários para carregar o AplicationContext e fazer o ciclo de vida? São eles o org.springframework.web.context.ContextLoaderListener e o org.springframework.web.context.request.RequestContextListener.
  6. Configurou o context-param contextConfigLocation dizendo qual seu arquivo XML do spring?

Se você fez tudo isso e aparenta estar tudo correto, da uma rodada em alguma classe de teste como desktop applicatione veja se as injeções nesses DAOs são feitas corretamente. Creio que não esqueci nenhum passo. Depois volta a postar aqui, quem sabe alguem alem de mim tenta te ajudar ^^ Estou tentando te ajudar a tanto tempo que vai ver eu fiquei tão viciado no seu codigo quanto você e também não consigo mais enxergar algum erro besta…

cris.t

Olá Guilherme!!!
Eu não estava injetando depêndencia na minha DAO, estava criando-a a partir de um new Object();
Agora fiz isso :slight_smile: :

&lt;bean name="/hello.htm" class="orm.controller.Teste" &gt;
		&lt;property name="productDAO" ref="productDAO" /&gt;
	&lt;/bean&gt;

Agora deu outro tipo de exception, dizendo não é possível cria a transação compartilhando o EntityManager e diz que eu use ou o Spring transaction ou um tal de EJB CMT:

SEVERE: Servlet.service() for servlet jpa threw exception
java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
	at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:163)
	at $Proxy9.getTransaction(Unknown Source)
	at orm.dataaccess.dao.ProductDAO.insert(ProductDAO.java:17)
	at orm.controller.Teste.handleRequest(Teste.java:30)
	at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
Guilherme_Gomes

Creio que eu sei o que é isso. Você está usando o filtro OpenEntityManagerInViewFilter com as annotations @Transactional, que fazem o trabalho de criar o EntityManager e o escopo de transação para você, além de todo o esquema de tratamento de exceções e rollback.

Mas, mesmo tendo todo esse controle do Spring, você deve estar fazendo algo do tipo:

@PersistenceContext
private EntityManager entityManager;

//...//

@Transactional
public void salvar(Entity entity){
  entityManager.getTransaction().begin();
  entityManager.persist(entity);
  entityManager.flush();
  entityManager.getTransaction().commit();
}

Se o próprio Spring se responsabiliza pelo ciclo de transação, pra que se preocupar usando essa forma declarativa? Substitua tudo isso por apenas:

@PersistenceContext
private EntityManager entityManager;

//...//

@Transactional
public void salvar(Entity entity){
  entityManager.persist(entity);
}
cris.t

Funcionoooouuu :smiley: :smiley: :smiley:

Era isso mesmo que estava acontecendo. Muito obrigada mesmo pela ajuda Guilherme, valew!! Agora só falta eu estudar bem esse código pra ter uma compreensão melhor.

Então esse JPaTransactionManager, vai fazer todo o controle de transação automático, mesmo quando for entre mais tabelas?

Guilherme_Gomes

Ele vai fazer o controle dentro do escopo de transação, seja la quantas tabelas você mexeu.

S

Meus amigos estou iniciando o estudo com Spring… estou tentando implementar exemplos pequenos para comecar entender como ele funciona.

No meu exemplo estou com a seguinte situacao.
Tenho um classe ApplicationContext.xml com os beans declarados… nao sei se estao declarados corretamente, alguem me ajude, por favor,

<?xml version="1.0" encoding="UTF-8"?>
<property name = "impressora" ref = "impressoraBean"/>
      <property name = "teclado" ref = "tecladoBean"/>
      <property name = "monitor" ref = "monitorBean"/>

</bean>

<bean id = "impressoraBean"
      class = "Impressora"/>

<bean id = "tecladoBean"
      class = "Teclado"/>

<bean id = "monitorBean"
      class = "Monitor"/>

estou implementando um classe para testar o exemplo, porem esta dando erro na declaracao do ApplicationContext e na classPathXmlApplicationContext

public class IniciaUsandoSpring {
public static void main(String[] args){

[color=red] ApplicationContext [/color]applicationContext = new [color=darkred]ClassPathXmlApplicationContext/color;

Computador computador = (Computador)
applicationContext.getBean(“computadorBean”);

computador.ligar();
}

}

sera que preciso configurar alguma coisa? ou importar alguma biblioteca?
alguem pode me ajudar?

Abraços
Ezequiel

cris.t

Olá Scopet,

estava dando uma olhada em seu código e vi que o nome do seu xml é applicationContext.xml e na sua classe vc está chamando o ApplicationContext.xml com A maiúsculo. o nome do arquivo deve ser igual. Qualquer coisa poste a exception.

Uma dica: quando for postar códigos use a tag code para formatação, assim fica mais fácil a visualização.

S

Meu amigo.. eu tinha criado o applicationContext, com a minusculo, depois renomei com o A maisculo pois achei q fosse isso,,,
mas nao resolveu..

nao ta reconhecendo o ApplicationContext e nem o ClassPathXmlApplicationContext

public class IniciaUsandoSpring {
    public static void main(String[] args){

   [color=red]ApplicationContext[/color] applicationContext = new [color=red]ClassPathXmlApplicationContext[/color](
           "classpath:applicationContext.xml");

   Computador computador = (Computador)
              applicationContext.getBean("computadorBean");

    computador.ligar();
    }
}
S

Opaa
Consegui resolver…

adicionei a biblioteca Spring Framework 2.5

e fiz as importacoes abaixo ai funcionou…

import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;

blz obrigado!

Criado 30 de abril de 2009
Ultima resposta 11 de fev. de 2010
Respostas 28
Participantes 3