EntityManager object is not getting injected with Glassfish and Spring - java

I have been trying to create a job to delete all records from database. This job is deployed with my webservice. In webservice I can easily access my EntityManager and it's having no issues so far. But, whenever I try to access EntityManager in my scheduler then it gives me NullPointerException. Even I have tried to inject a service that I have created and tried to access it's method. The method which have no database related work is working fine and returning me result. But, the method which is using entityManager inside is throwing me the same exception.
While if I directly call the service using URL each and everything works fine in service as well.
#Service
public class DeletionJob {
#PersistenceContext(unitName = "my_pu")
private EntityManager em;
#Autowired
private REST restClass;
#Scheduled(fixedDelay=10000)
public void run() {
boolean flag = false;
System.out.println(restClass.executeWithoutDB());
System.out.println(restClass.executeWithDB());
}
}
Configuration Class:
#EnableWebMvc
#Configuration
#EnableScheduling
#ComponentScan({ "com.jobs.*" })
#javax.ws.rs.ApplicationPath("webresources")
public class AppConfig extends Application {
#Bean
public DeletionJob myDeletionJob() {
return new DeletionJob();
}
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver
= new InternalResourceViewResolver();
return viewResolver;
}
#Bean
public REST restClass(){
return new REST();
}
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<Class<?>>();
addRestResourceClasses(resources);
return resources;
}
/**
* Do not modify addRestResourceClasses() method.
* It is automatically populated with
* all resources defined in the project.
* If required, comment out calling this method in getClasses().
*/
private void addRestResourceClasses(Set<Class<?>> resources) {
resources.add(com.service.REST.class);
// Tried to include deletionjob class here but, no luck still the same.
// resources.add(com.jobs.DeletionJob.class);
}
}
persistance.xml file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="my_pu" transaction-type="JTA">
<jta-data-source>ds</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.logging.level" value="FINE"/>
</properties>
</persistence-unit>
</persistence>
I have also tried to use this PersistenceAnnotationBeanPostProcessor component. But after including spring-orm it has even started giving me excpetion of BeanInitializationException. Secondly, I am not fond of using too many libraries. So, would like to do this thing in a simplest possible way. I could do it by looking up JNDI, but, the problem is that I want to use Spring or JAVA EE 6 scheduler API.
Version of GlassFish Server: 4.1

#PersistenceContext is simply getting ignored here.
An entity manager can only be injected in classes running inside a transaction.
Use an EntityManagerFactory to create and destroy an EntityManager.
#PersistenceUnit(unitName = "my_pu")
private EntityManagerFactory entityManagerFactory;
And inside your method use below line to create EntityManager:-
EntityManager entityManager = entityManagerFactory.createEntityManager();
Refer this link:- Injection of Persistence Context in spring
I feel your Persistence Context is not getting initialized properly.

Related

Dependencies not Autowired when using an xml Entity Listener [duplicate]

This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 5 years ago.
I am currently working on a project where I need to audit my Entities. To do this we are using an Entity Listener configured in an xml file (This was required by the architecture of the project, no annotations were allowed) : see this documentation
We are also working using DDD (Domain Driven Design) so our application is using Domain/Application/Infrastructure layers and also WebApp (The latter allows you to start the application and do requests on it).
Here is my entity configuration :
<entity-mappings version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm_2_1.xsd" >
<persistence-unit-metadata>
<persistence-unit-defaults>
<entity-listeners>
<entity-listener class="com.company.infra.application.service.impl.MyServiceASImpl">
<post-persist method-name="handlePostPersist"/>
<post-update method-name="handlePostUpdate"/>
<pre-remove method-name="handlePreRemove"/>
</entity-listener>
</entity-listeners>
</persistence-unit-defaults>
</persistence-unit-metadata>
</entity-mappings>
This is actually working. The methods located in MyServiceASImpl are correctly called. The problem is that the different services available as #Autowired are not injected correctly and I get a null pointer exception when they are used.
Here is the code of MyServiceASImpl :
package com.company.infra.application.service.impl;
// ... Different necesssary imports
#ApplicationService // This is a custom annotation
#Transactional(propagation = Propagation.REQUIRED) // To propagate exceptions
public class MyServiceASImpl implements MyServiceAS {
private static final Logger LOGGER = LoggerFactory.getLogger(MyServiceASImpl.class);
#Autowired
private com.company.domain.service.MyServiceDS mysServiceDS; // This is in the domain layer
#Autowired
private TransversalService transversalService;
#Autowired
private com.company.domain.model.myRepository myRepository; // Interface in domain layer but implementation in infrastructure layer
// ... Other methods
public void handlePostPersist() {
// Calls to on of the services
}
public void handlePostUpdate() {
// Calls to on of the services
}
public void handlePreRemove() {
// Calls to on of the services
}
}
I have several xml configuration to do component-scan on the necessary packages.
Furthermore, if this service is called from a webservice contained in the webapp layer, the dependencies are injected correctly.
But, when the Entity Listener is triggered and class theses, all three dependencies are null.
Has anyone encountered this problem ? How can autowire the dependencies correctly ?
Don't hesitate to ask for more details.
Thanks for your help.
Since the entity listener is not managed by Spring, you cannot use #Autowired. So you need to use a static injection:
public class MyServiceASImpl implements MyServiceAS {
public void preRemove(final Object objet) {
ApplicationContextProvider.getApplicationContext().getBean(MyRepository.class)
.gererAuditCasPreSuppression(objet);
}
}
Make sure to modify your xml file in order to call the methods.
You will have to right an application context provider :
package leclerc.wrf.commun;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
#Component
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
protected ApplicationContextProvider() {
}
#Override
public void setApplicationContext(final ApplicationContext applicationContext) {
ApplicationContextProvider.context = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return ApplicationContextProvider.context;
}
}
I'm afraid but this will not work because the entity listener is managed by JPA and the Spring dependency injection will not work.
Please have a look at the solutions mentioned here:
Injecting a Spring dependency into a JPA EntityListener

Managing Multiple Database Connections

I've been struggling with this problem for days,
Here is the scenario:
I have several databases, one for each of my customers, all of them with the same
structure(same tables and columns), so my application needs to decide at runtime with which one it needs to connect. I'm using JPA2, EclipseLink and EJB3.
My first attempt was to implement a custom EntityManager with all the logic to performs the operations on the right database, then I configured this EntityManager as an Stateless EBJ in order to make it possible to inject it with the #EBJ annotation (as described at this link: http://www.hostettler.net/blog/2012/11/20/multi-tenancy/). I coundn't make it work because it was throwing an exception when trying to inject the EntityManager.
So I decided to try something else, I've created EntityManagerFactory and I passed the
JTA_DATASOURCE to it(after decide at runtime which one to use), so it could connect to the
right database.
Here is the code:
#Stateless
#TransactionManagement(TransactionManagementType.CONTAINER)
public class TestEntDAO {
private EntityManager em;
private EntityManagerFactory emf;
#PostConstruct
public void init() {
em = getEntityManager();
}
public EntityManager getEntityManager() {
Map props = new HashMap();
props.put(PersistenceUnitProperties.TRANSACTION_TYPE, "JTA");
props.put(PersistenceUnitProperties.JTA_DATASOURCE, dataSourceName());
emf = Persistence.createEntityManagerFactory("testePU", props);
em = emf.createEntityManager();
return em;
}
public String dataSourceName(){
if(someCondition){
return "db1";
}else{
return "db2";
}
}
}
This worked perfectly, the only problem is that the transaction is not managed by the
container, so I had to explicitly mark the transaction's boundaries(call begin() and
commit()). I could just use the #PersistenceContext annotation to make it work, but then I
wouldn't have the EntityManagerFactory to pass the datasource.
Does anyone know of a way to use the Container-Managed Transactions(CMT) and still be able
to pass the datasource?
Maybe try to define 3 Data sources and 3 Persistence units.
<persistence-unit name="PU1">
<jta-data-source>jdbc/DS1</jta-data-source>
...
</persistence-unit>
<persistence-unit name="PU2">
<jta-data-source>jdbc/DS2</jta-data-source>
...
</persistence-unit>
<persistence-unit name="PU3">
<jta-data-source>jdbc/DS3</jta-data-source>
...
</persistence-unit>
And inject Entity manager from whatever Persistence unit you want.
#PersistenceContext(unitName = "PU2")
EntityManager em;
This should work, although I didn't test it.

JPA deceleration exception

I am using jboss5.1.x EJB3.0
I am trying my first time with JPA, and I get this exception when I run the server:
java.lang.IllegalArgumentException: Can't find a persistence unit named 'java:/mracDS'
..
this is my "DAO" entity which is responsible on all the JPA entities:
#Stateless
public class ECMSEntityManagerDao implements ECMSEntityManagerDaoLocal, ECMSEntityManagerDaoRemote
{
#PersistenceContext(unitName = "java:/mracDS")
EntityManager em;
public ArrayList<T01CounterCalls> getClocksDetailsFromVantive() throws SQLException
{
return (ArrayList<T01CounterCalls>) em.createQuery ("from T01CounterCalls as data").getResultList ();
}
}
I looked a bit in the net:
I never declared persistence.xml
and if I do, what should be declared inside?
thanks,
ray.
From the look of it my guess is that you are confusing a persistence unit with a data source.
These two may feel similar, but they aren't. Very simply said a persistence unit is a set of classes plus an associated data source. In the most basic form, a persistence unit merely couples to a data source:
persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"
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="mracPU">
<jta-data-source>java:/mracDS</jta-data-source>
</<persistence-unit>
</persistence>
Then use the persistence unit name with the injection annotations:
#Stateless
public class ECMSEntityManagerDao implements ECMSEntityManagerDaoLocal, ECMSEntityManagerDaoRemote {
#PersistenceContext(unitName = "mracPU")
EntityManager em;
}

What to put into jta-data-source of persistence.xml?

What value should I place into <jta-data-source> of my persistence.xml?
In glassfish admin panel I created a datasource name "abcDS". In my jndi.properties (inside src/test/resources) I defined it like this:
[...]
abcDS=new://Resource?type=DataSource
abcDS.JdbcDriver=org.hsqldb.jdbcDriver
abcDS.JdbcUrl=jdbc:hsqldb:mem:testdb
abcDS.JtaManaged=true
[...]
What shall I place into persistence.xml? I've found a lot of variants in the Net, like: "jdbc/abcDS", "java:/abcDS", "abcDS". Which one is right? And is there some rule for this? I understand that it's related to JNDI, but...
I'm trying to create EMF in my unit test:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("abc");
This is what I'm getting in log:
[...]
SEVERE: Could not find datasource: abcDS javax.naming.NameNotFoundException:
Name "abcDS" not found.
at org.apache.openejb.core.ivm.naming.IvmContext.federate(IvmContext.java:193)
at org.apache.openejb.core.ivm.naming.IvmContext.lookup(IvmContext.java:150)
at org.apache.openejb.core.ivm.naming.ContextWrapper.lookup(ContextWrapper.java:115)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
[...]
The problem is that Persistence.createEntityManagerFactory("abc") is the "do it yourself" API and doesn't take advantage of the Embedded EJB Container. You can get a container managed EntityManager in your test case very easily.
Just as with the related jndi/datasource question I recommend you check out the examples in the examples.zip. They're all designed to take the struggle out of getting started.
Here's a snippet from the testcase-injection example which shows how you can get an EntityManager and other things from the container for use in a test.
First, add an empty ejb-jar.xml or application-client.xml to your test to turn on scanning for your test code:
src/test/resources/META-INF/application-client.xml
Then, annotate your test case with #org.apache.openejb.api.LocalClient and use the standard JavaEE annotations for the actual injection.
#LocalClient
public class MoviesTest extends TestCase {
#EJB
private Movies movies;
#Resource
private UserTransaction userTransaction;
#PersistenceContext
private EntityManager entityManager;
public void setUp() throws Exception {
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
p.put("movieDatabase", "new://Resource?type=DataSource");
p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver");
p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb");
InitialContext initialContext = new InitialContext(p);
// Here's the fun part
initialContext.bind("inject", this);
}
As movieDatabase is the only DataSource that we've setup, OpenEJB will automatically assign that DataSource to your persistence unit without the need to modify your persistence.xml. You can even leave the <jta-data-source> or <non-jta-data-source> empty and OpenEJB will still know what to do.
But for the sake of completeness, here's how this particular application has defined the persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<persistence-unit name="movie-unit">
<jta-data-source>movieDatabase</jta-data-source>
<non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
<class>org.superbiz.testinjection.Movie</class>
<properties>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
</properties>
</persistence-unit>
</persistence>
Then the fun part, using it all together in tests
public void test() throws Exception {
userTransaction.begin();
try {
entityManager.persist(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
entityManager.persist(new Movie("Joel Coen", "Fargo", 1996));
entityManager.persist(new Movie("Joel Coen", "The Big Lebowski", 1998));
List<Movie> list = movies.getMovies();
assertEquals("List.size()", 3, list.size());
for (Movie movie : list) {
movies.deleteMovie(movie);
}
assertEquals("Movies.getMovies()", 0, movies.getMovies().size());
} finally {
userTransaction.commit();
}
}

Using injected EntityManager in class hierarchies

The following code works:
#Stateless
#LocalBean
public class MyClass
{
#PersistenceContext(name = "MyPU")
EntityManager em;
public void myBusinessMethod(MyEntity e)
{
em.persist(e);
}
}
But the following hierarchy gives a TransactionRequiredException in Glassfish 3.0 (and standard JPA annotations with EclipseLink.) at the line of persist.
#Stateless
#LocalBean
public class MyClass extends MyBaseClass
{
public void myBusinessMethod(MyEntity e)
{
super.update(e);
}
}
public abstract class MyBaseClass
{
#PersistenceContext(name = "MyPU")
EntityManager em;
public void update(Object e)
{
em.persist(e);
}
}
For my EJB's I collected common code in an abstract class for cleaner code. (update also saves who did the operation and when, all my entities implement an interface.)
This problem is not fatal, I can simply copy update and sister methods to subclasses but I would like to keep all of them together in a single place.
I didn't try but this may be because my base class is abstract, but I would like to learn a proper method for such a (IMHO common) use case.
AFAIK, you can't inject into a super class, so you have to inject into a field or method of the actual EJB. You could do something like this:
public class MyBaseEJB {
public abstract EntityManager getEM();
public void update(Object e) {
getEM().persist(e);
}
}
#Stateless
public class MyEJB extends MyBaseEJB {
#PersistenceContext
EntityManager em;
public EntityManager getEM() { return em;}
}
Update: I was wrong, according to the section 5.2.3 of the Java EE 5 platform specification, injection is allowed in super class fields and methods.
I went a bit further and did a small test on my side using similar code, GlassFish v3 and EclipseLink and I can't reproduce your problem. So I suspect some kind of problem with your persistence.xml. Could you provide it? Are you using a transaction-type="JTA"? Just in case, here is the one I used:
<?xml version="1.0" encoding="UTF-8"?>
<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 persistence_2_0.xsd" version="2.0">
<persistence-unit name="MyPU" transaction-type="JTA">
<!-- EclipseLink -->
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/q2484443</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="database"/>
</properties>
</persistence-unit>
</persistence>
BTW, I think that it's perfectly fine to skip the DAO pattern for simple data access operations. Have a look at this previous answer.
Your approach isn't wrong (if it works)
However it is more common to either use (inject) a Dao and call methods on it, or if the Dao is a redundant layer that only wraps the EntityManager, you can simply call the methods on EntityManager directly. Of course, exposing the EntityManager to subclasses via a protected getter.
getEntityManager().persist(e);
The problem was not using superclass' injected entity manager, but calling another EJB's method: e.g.
#Stateless
#LocalBean
public class MyBean extends MySuperBean
{
#EJB
com.example.project.MyOtherBean otherBean;
public boolean myService(String userName, MyEntity entity)
{
if(otherBean.checkAuthority(userName))
{
super.insert(entity);
}
}
}
I was using this pattern when OtherBean was not a bean and checkAuthority was a static method using (non-JTA) EntityManagerFactory. Then I changed OtherBean to extend MySuperBean too. I think, in this case, when OtherBean ends checkAuthority, JTA ends the transaction and MySuperBean's insert can't find a transaction to persist entity. Understandably Stateless EJB's don't let fellow EJB's to proceed the transaction.
As Pascal, I initially thought that injection does not work with inheritance but this problem continued when I directly called em.persist() in the subclass. After this I finally was able to check other possible causes.
Thanks for all the input.

Categories

Resources