问题
This question is specific to broadleaf commerce. I have to load an entity in a static method. Since injecting entityManager would not help (as i cannot access it in a static method), i am not able to load the entity.
I tried using Persistence.createEntityManagerFactory, but it does not help. Here is my sample code.
Query query = Persistence.createEntityManagerFactory("blPU").createEntityManager().createQuery("some query");
List results = query.getResultList();
The error i am getting:-
javax.persistence.PersistenceException: No Persistence provider for EntityManager named blPU
For cases when i have to use it normaly in instance methods, entityManager works like a charm:
@PersistenceContext(unitName="blPU")
protected EntityManager em;
So i guess it is not any classpath issue. Any help would be great.
回答1:
If you don't actually need to write your query in a static context but still want to access an entity in a static method, I'll give you the suggestion to just find an existing instance of an EJB through CDI-context with the following generic code:
public class Util {
private static <T> T lookUpClassInBeanManager(Class<T> clazz) {
BeanManager bm = CDI.current().getBeanManager();
Bean<T> bean = (Bean<T>) bm.getBeans(clazz).iterator().next();
CreationalContext<T> ctx = bm.createCreationalContext(bean);
return (T) bm.getReference(bean, clazz, ctx);
}
public static YourDaoClass lookUpYourDaoClass() {
return lookUpClassInBeanManager(YourDaoClass.class);
}
}
Your DaoClass looks like that:
@Stateless
public class YourDaoClass {
@PersistenceContext(unitName = "blPU", type = PersistenceContextType.TRANSACTION)
protected EntityManager em;
public <T> List<T> getEntityListByType(Class<T> clazz) {
TypedQuery<T> query = em.createQuery("select entity from "+ clazz.getSimpleName() +" entity", clazz);
return query.getResultList();
}
}
In a static method this can be used like that:
public static void tryEJBinStaticContext() {
YourDaoClass dao = Util.lookUpYourDaoClass();
List<SomeEntity> list = dao.getEntityListByType(SomeEntity.class);
}
回答2:
To be clear it's bad idea to get EntityManagerFactory
over the Peristence.createEntityManagerFactory
inside of enterprise container, use container capability instead. If you need Peristence.createEntityManagerFactory
outside of container let say, for test only or for other reasons. You have to create Java SE JPA context, I created this example project to explain how to do it for JPA testing.
Here some project notices for better understanding, if you plan to do it by you self.
Most important part is create only one persistence.xml
, avoid to create an other one for the tests, overwrite settings of you persistence.xml
instead. This should be enough for you persistence.xml:
<persistence-unit name="application-ds" transaction-type="JTA">
<jta-data-source>java:/youApplication</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
</persistence-unit>
In example project I add some properties for database generation, but this not necessary maybe you have another way to prepare you database.
To create your EntityManagerFactory
, pass persistence unit name (this is important),together with properties map to Persistence.createEntityManagerFactory. With this step you set up
persistence provider for java se. It exists some limitation, first we haven't any JTA and JPA can't auto discover the entity classes.
Here the most important properties:
properties.put("javax.persistence.transactionType", "RESOURCE_LOCAL");
properties.put("javax.persistence.provider", "org.hibernate.jpa.HibernatePersistenceProvider");
properties.put("javax.persistence.jtaDataSource", null);
properties.put("hibernate.archive.autodetection", "class");
The next trick is how to inject or persistence provider into the ejb, and mockito is the solution. Code first:
@InjectMocks
private UserDao dao;
@Spy
private EntityManager em;
@Before
public void prepare() {
em = JpaProvider.instance().getEntityManager();
initMocks(this);
}
Explanation: Mockito is used to inject entity manager into the ejb. Mark EntityManager as spied object, and initialize it in @Before
test method, then call initMocks
on test class that's all.
Last but not least don't forget to create, and commit transactions, because you don't have container to do it for you.
回答3:
A Broadleaf specific answer (if you need a blPU EntityManager) is to use:
GenericEntityDaoImpl.getGenericEntityDao().getEntityManager();
来源:https://stackoverflow.com/questions/37771566/how-to-get-a-static-instance-of-entitymanager-in-broadleaf