I've been banging my head on the wall for the past couple of days trying to get this to work but I've not been able to.
I wrote a JPA EntityManagerProvider recently using EJB:
EntityManagerProviderBean.java
#Stateless
public class EntityManagerProviderBean {
#PersistenceContext(unitName="PU1")
private EntityManager entityManager1;
#PersistenceContext(unitName="PU2")
private EntityManager entityManager2;
public EntityManager getEntityManager() {
return (...) ? entityManager1: entityManager2;
}
}
And then of course I can inject the EJB wherever needed like this:
UserFacade.java
#Stateless
public class UserFacade {
#EJB
private EntityManagerProviderBean emProvider;
private EntityManager em = emProvider.getEntityManager();
...
}
Now I'm trying to do something similar using Spring, using annotations, and without doing anything in XML. I can't seem to figure out a way to inject the EntityManager. Anything that I do leads to a NullPointerException. For example, I tried to inject the EntityManager manually without relying on my EntityManagerProviderBean, like this:
UserFacadeSpring.java
public class UserFacadeSpring {
#PersistenceContext(unitName="PU1")
private EntityManager em;
...
}
But this gives me a NullPointerException. So the EntityManager is not being injected at all and I'm not sure what's wrong.
So two questions basically:
How can I inject the EntityManager using Spring?
How can I use my existing EntityManagerProviderBean EJB in Spring? What modifications do I need to make?
Any help in this matter will be greatly appreciated. As you can tell I'm a complete noob to Spring. I tried to read the guide but everything's flying over my head at the moment. I actually did try to do something half-baked but it didn't work either (I either get NullPointerException or BeanNotFoundException, I must have used every combination of #Component, #Bean, #Autowired annotations I think!):
EntityManagerProviderSpring.java
#Component
public class EntityManagerProviderSpring {
#PersistenceContext(unitName="PU1")
private EntityManager entityManager1;
#PersistenceContext(unitName="PU2")
private EntityManager entityManager2;
#Bean
public EntityManager getEntityManager() {
return (...) ? entityManager1: entityManager2;
}
}
Main.java
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(EntityManagerProviderSpring.class);
EntityManagerProviderSpring emProvider = context.getBean(EntityManagerProviderSpring.class);
EntityManager em = emProvider.getEntityManager();
...
}
Thanks!
EDIT: I'm using Hibernate with JPA and the following is my persistence.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="PU1" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>...</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/db1?zeroDateTimeBehavior=convertToNull"/>
<property name="javax.persistence.jdbc.user" value="pu1_username"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.password" value="pu1_pwd"/>
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
</properties>
</persistence-unit>
<persistence-unit name="PU2" transaction-type="RESOURCE_LOCAL">
...
</persistence-unit>
</persistence>
To have the exact same functionality on dependency injection level, it is impossible to map stateless ejb bean to a spring bean.
EJB #Singleton -> Spring #Component (or #Service or #Controller or #Repository)
EJB #Stateful -> Spring #Component#Scope("prototype") (or #Service#Scope("prototype") or #Controller#Scope("prototype") or #Repository#Scope("prototype"))
EJB #Stateless -> DOES NOT EXIST IN SPRING.
Stateless beans are very handy for this multiple persistence contexts... However, since Spring doesn't offer stateless bean. You have to use custom Spring setup to apply multiple persistence context. It won't work with only persistence.xml like EJB, unfortunately :(.
So to answer your questions:
Read Spring doc... Plenty of examples everywhere. Shortly, In Spring 4 Java Config you can use #EnableTransactionManagement, a transaction manager and an entity manager factory per persistence context.
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/ejb.html. This is how you do it. Not a nice way since using jndi, but it is a solution...
Related
Why post construct does not get called without putting bean in applicationContext.xml
Here is my class which contains #PostConstruct annotation.
package org.stalwartz.config;
import javax.annotation.PostConstruct;
import javax.inject.Singleton;
#Singleton
public class PropertyLoader {
#PostConstruct
public void init() {
System.out.println("PropertyLoader.init()");
}
}
Below is my applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.directwebremoting.org/schema/spring-dwr
http://www.directwebremoting.org/schema/spring-dwr/spring-dwr-3.0.xsd">
<dwr:annotation-config />
<dwr:annotation-scan base-package="org.stalwartz" scanDataTransferObject="true" scanRemoteProxy="true" />
<dwr:url-mapping />
<!-- <bean id="proeprtyLoader" class="org.stalwartz.config.PropertyLoader"></bean> -->
<dwr:controller id="dwrController" debug="false">
<dwr:config-param name="activeReverseAjaxEnabled" value="true" />
</dwr:controller>
<context:annotation-config>
<context:component-scan base-package="org.stalwartz" annotation-config="true"></context:component-scan>
</context:annotation-config>
<mvc:annotation-driven />
...
...
...
</beans>
Looks simple, but it does not work without uncommenting bean declaration.
In Spring environment initialization callback method (the one annotated by #PostConstruct) make sense only on spring-managed-beans. To make instance(s) of your PropertyLoader class managed, you must do one of the following:
Explicitly register your class in context configuration (as you did)
<bean id="proeprtyLoader" class="org.stalwartz.config.PropertyLoader"></bean>
Let component scanning do the work (as you nearly did), but classes must be annotated by one of #Component, #Repository, #Service, #Controller.
Note from Spring documentation: The use of <context:component-scan> implicitly enables the functionality of <context:annotation-config>. There is usually no need to include the <context:annotation-config> element when using <context:component-scan>.
Because putting bean in applicationContext.xml you are adding bean to Spring container, which has interceptor for this annotation. When Spring inject beans it checks #PostConstruct annotation, between others.
When you call simple new PropertyLoader() JVM will not search for the #PostConstruct annotation.
From doc of #PostConstruct annotation:
The PostConstruct annotation is used on a method that needs to be executed
after dependency injection is done to perform any initialization. This
method MUST be invoked before the class is put into service. This
annotation MUST be supported on all classes that support dependency
injection. The method annotated with PostConstruct MUST be invoked even
if the class does not request any resources to be injected.
Singleton is a scope annotation. It can be used to declare 'singletone' scope for a particular bean, but not instantiate it. See this article.
If you want to instantiate your class as singleton you can try Spring Service annotation.
#Service
public class PropertyLoader {
#PostConstruct
public void init() {
System.out.println("PropertyLoader.init()");
}
}
Also, you can replace annotation-config tag with component-scan. Here is a good article about differences of annotation-config and component-scan tags.
you are using #Singleton from javax.inject package which is not picked up as bean by spring container. Change it to :
package org.stalwartz.config;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
#Component
public class PropertyLoader {
#PostConstruct
public void init() {
System.out.println("PropertyLoader.init()");
}
}
and the spring will auto detect PropertyLoader and will include it in Spring container as bean via the #Component annotation and this bean will be with singleton scope
by default a bean is singleton scoped in Spring, and #PostConstruct is usually used for service beans and service beans must scoped prototype and here because you need multiple objects for that particular class, Spring will provide you singleton instance.
also by doing this spring will attempt multiple times to find this service bean and finally throws below exception:
java.lang.NoClassDefFoundError: Could not initialize class org.springframework.beans.factory.BeanCreationException
so try like this in annotation way:
package org.stalwartz.config;
import javax.annotation.PostConstruct;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
#Component
#Scope("prototype") //you have to make it prototype explicitly
public class PropertyLoader {
#PostConstruct
public void init() {
System.out.println("PropertyLoader.init()");
}
}
Now every thing is good, and work fine for you.
add this dependency to pom.xml
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
I have a multi-module Spring application where each module (jar) contains its own persistence.xml.
In jar 1
Persistence.xml
<persistence-unit name="pu_one" transaction-type="RESOURCE_LOCAL">
...
</persistence-unit>
EntityOne.java
#Entity
public class EntityOne {
}
EntityOneRepository.class
interface EntityOneRepository extends JpaRepository<EntityOne, Long> {
}
In jar 2:
persistence.xml
<persistence-unit name="pu_two" transaction-type="RESOURCE_LOCAL">
...
</persistence-unit>
EntityTwo.java
#Entity
public class EntityTwo {
}
EntityTwoRepository.class
interface EntityTwoRepository extends JpaRepository<EntityTwo, Long> {
}
Then I use a org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager to put them all together.
My issue is with regards to the JpaRepositories as they are using the default persistence unit, as defined in the configuration of the DefaultPersistenceUnitManager.
Question. How to I instruct each of the repositories to use the correct persistence unit?
I ended up of using
org.springframework.data.jpa.support.MergingPersistenceUnitManager
Instead of the
org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager
Then all of the entities in different jars will be merged into one persistence unit. The trick was to name all persistence units the same.
However I would prefer to inform each repository what persistence unit to use, this works for now.
I have simple maven EJB module using JPA. This is my persistance.xml file
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="Persistence">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<mapping-file>GroupTypes.xml</mapping-file>
<properties>
<property name="hibernate.connection.url" value="jdbc:oracle:thin:#127.0.0.1:1521:E"/>
<property name="hibernate.connection.driver_class" value="oracle.jdbc.driver.OracleDriver"/>
<property name="hibernate.connection.username" value="username"/>
<property name="hibernate.connection.password" value="password"/>
</properties>
</persistence-unit>
</persistence>
I am using EJB Stateless Bean and I am trying to get all attributes from GroupTypes table. This is my bean implementation:
public class TestBean
{
private GroupTypes GroupTypes;
private EntityManagerFactory entityManagerFactory;
private EntityManager entityManager;
#WebMethod (operationName = "justTesting")
public boolean justTesting(#WebParam (name = "param") String value)
{
try
{
entityManagerFactory = Persistence.createEntityManagerFactory("Persistance");
entityManager = entityManagerFactory.createEntityManager();
Query query = entityManager.createQuery("Select name from GroupTypes");
List<AmmEdGroupTypes> result = query.getResultList();
return true;
}
catch(Exception e)
{
e.printStackTrace();
return false;
}
}
}
When I try to invoke this method I get exeption: javax.persistence.PersistenceException: No Persistence provider for EntityManager named Persistance.
My persistance.xml file is placed in folder resources/META-INF/persistance.xml, and if I am not using bean this solution works. Does anydbody have some idea why this is happening only in case when I am using bean?
I am using Intellij 12.1.1, Oracle 11g, Glassfish 3.1 server and JAVA 1.6.
I solved this problem in the following way:
Installed hibernate add-on on glassfish (using glassfish update tool)
On glassfish added jdb connection pool _AmmPool with properties: className, username,password,databaseName and url
On glassfish added jdbc resource jdbc/__amm binding with connection pool _AmmPool
Changed persistence.xml file
Changed pom.xml file
Copied the following libraries into glassfish domains/domain1/lib folder:
antlr-2.7.7
commons-collections-3.2.1,
dom4j-1.6.1,
ejb3-persistence-1.0.2.GA,
hibernate3-maven-plugin-3.0,
hibernate-commons-annotations-4.0.2.Final,
hibernate-core-4.2.2.Final,
hibernate-entitymanager-4.2.2.Final,
javassist-3.15.0-GA,
jta-1.1,
log4j-1.2.17,
oracle-jdbc-11.1.0.6.0-Production+,
slf4j-api-1.6.1
slf4j-log4j12-1.7.5
A also copied these libraries into glassfish/lib floder.
This is my new persistance.xml file: http://pastebin.com/xbEU9Tr0
And this is my pom.xml file: http://pastebin.com/uEjhW36
Anything like #PreDestroy in the spring-framework?
If you define a bean that implements the DisposableBean interface then Spring will call the
void destroy() throws Exception;
method before destrying the bean.
That's one way, the other is when your bean doesn't have to implement the given interface.
In one of yours ConfigurationSupport classes your bean has to be defined as as pulic method with the #Bean annotation.
#Bean (destroyMethod="yourDestroyMethod")
public YourBean yourBean() {
YourBean yourBean = new YourBean();
return yourBean;
}
The method "yourDestroyMethod" has to be defined in YourBean.class and then Spring will call it before destroying the bean.
For more info see the Spring documentation: Destruction callbacks
UPDATE
The third way... I would even say the better way would be to specifiy "init-method" and "destroy-method" of your bean... like this: mkyong.com/spring/spring-init-method-and-destroy-method-example
This solves the problem ot third-party dependency beans, and liberates the the code unnecessary Spring interfaces..
There are 3 ways to do that.
#PreDestroy tag
destroy-method in xml
DisposableBean interface as stated above
My favorite is the #PreDestroy method.
To do that u need:
In application-context.xml add the following schema:
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="shutDownBean" class="spring.ShutDownBean" />
<context:annotation-config/>
</beans>
The context:annotation-config/ makes the #PreDestroy and the #PostDestroy tags available.
Now lets say that you have the ShutDownBean that you want to run some code when the shutdown callback is called.
The <bean id="shutDownBean" class="spring.ShutDownBean" /> part registers the bean.
import javax.annotation.PreDestroy;
public final class ShutDownBean {
#PreDestroy
public static void shutDownMethod() {
System.out.println("Shutting down!");
}
}
Now you are done.
If you have a desktop application then to use the #PreDestroy annotation you need to close it like this:
AbstractApplicationContext applicationContext =
new ClassPathXmlApplicationContext("application-context.xml");
applicationContext.registerShutdownHook();
note:
AbstractApplicationContext has the implementation of registerShutdownHook() so this is the minimum class you can use.
Also you can use the destroy-method tag for classes you do not control their implementation. For example you can add this in your applcation-context.xml:
<bean id = "dataSource"
class = "org.apache.commons.dbcp.BasicDataSrouce"
destroy-method = "close">
The destroy-method value can have any visibility but needs to have no arguments.
Hope this helps!
You mean like annotating a method with the standard JDK #PreDestroy? That's common enough in Spring, and usually better than using a destroy-method attribute on the bean declaration in XML. All you have to do is include
<context:annotation-config/>
In your configuration file and Spring handles the rest.
there's standard .NET IDisposable.Dispose() method. I don't know Spring but from quick googling it seems that #predestroy is pretty much the same concept.
I think I've read every question and answer on Spring and autowiring a servlet, both here and at springsource.org, and I still can't get it working.
All I want to do is have the datasource automatically set in my servlets. I understand that the container creates the servlet and not Spring.
Here is code from my test servlet:
package mypackage.servlets;
imports go here...
#Service
public class TestServlet extends HttpServlet
{
private JdbcTemplate _jt;
#Autowired
public void setDataSource(DataSource dataSource)
{
_jt = new JdbcTemplate(dataSource);
}
etc etc
In my applicationContext.xml I have:
<context:annotation-config />
<context:component-scan base-package="mypackage.servlets />
<import resource="datasource.xml" />
and in my datasource.xml:
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/db" />
If I can't get this working I'll just use WebApplicationContextUtils in the servlet's init method but I'd really like to make this work after all the reading I've been doing.
I'm using Spring 3, Java 1.6.
Thanks,
Paul
You need to replace your Servlets by Spring MVC contollers. Because Spring will not inject anything the classes (servlets) created by someone else then Spring itselfe (except #Configurable).
(To get an very simple example, take a look at the STS Spring Template Project: MVC).
What I wanted to do was get a DataSource reference in my Servlet for free, i.e. not calling a static getDatasource method on some class.
Here's what I learned and how I got it working:
Servlets cannot be configured or autowired by Spring. Servlets are created before Spring's app context is loaded. See issue SPR-7801: https://jira.springsource.org/browse/SPR-7801
What I did was create a DataSource in my applicationContext.xml and export that as a property:
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/db" />
<bean class="org.springframework.web.context.support.ServletContextAttributeExporter">
<property name="attributes">
<map>
<entry key="myDatasource">
<ref bean="dataSource"/>
</entry>
</map>
</property>
</bean>
In my servlet's init method I read the property:
public void init(ServletConfig config)
{
Object obj = config.getServletContext().getAttribute("myDatasource");
setDataSource((DataSource)obj);
}
public void setDataSource(DataSource datasource)
{
// do something here with datasource, like
// store it or make a JdbcTemplate out of it
}
If I'd been using DAOs instead of hitting the database from the servlets it would have been easy to wire them up for #Autowired by marking them #Configurable, and also be able to use #Transactional and other Spring goodies.