I'm trying to get CDI (with Open Web Beans) working from within a unit test using Delta Spike (#RunWith(CdiTestRunner.class)). Dependency injection is working fine but my EntityManagerFactory is always null:
public class EntityManagerProducer {
#PersistenceContext(unitName = "sbPersistenceUnit")
private EntityManagerFactory emf; //Always null
#Produces
public EntityManager create() {
return emf.createEntityManager();
}
public void close(#Disposes EntityManager em) {
if (em.isOpen()) {
em.close();
}
}
}
I know that my persistence.xml is okay because I can create the Session Factory manually:
EntityManagerFactory test = Persistence.createEntityManagerFactory("sbPersistenceUnit");
and all other injections are working fine. Does anybody know what might be missing?
In an unit-test you aren't in a managed environment.
OpenWebBeans would support it via the openwebbeans-resource module + #PersistenceUnit, but that isn't portable.
So you need to use e.g.:
#Specializes
public class TestEntityManagerProducer extends EntityManagerProducer {
private EntityManagerFactory emf = Persistence.createEntityManagerFactory("...");
#Produces
//...
#Override
protected EntityManager create() {
return emf.createEntityManager();
}
#Override
protected void close(#Disposes EntityManager em) {
if (em.isOpen()) {
em.close();
}
}
}
in the test-classpath
If you ask such questions on their mailing-list, you get answers petty quickly.
You will need to use #PersistenceUnit to inject EntityManagerFactory. #PersistentContext is used for EntityManager injection.
Do you define your entitymanagerFactory as a bean?
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
Related
I tried create BaseDao and inject EntityManager to it. In Spring I was make this:
public abstract class BaseJpaDao<E> implements BaseDao<E>{
protected Class<?> entityClass;
#PersistenceContext(unitName = "access")
protected EntityManager entityManager;
public BaseJpaDao(Class<?> entityClass) {
this.entityClass = entityClass;
}
#Override
public E persist(E e) {
entityManager.persist(e);
return e;
}
but now I tried make this in OSGI and I not understand how do it. I treid write in blueprint.xml
<bean id="baseJpaDao" class="domain.access.impl.BaseJpaDao" >
<jpa:context unitname="access" property="entityManager"/>
<tx:transaction method="*" value="RequiresNew"/>
</bean>
and after this
public abstract class BaseJpaDao<E> implements BaseDao<E>{
protected Class<?> entityClass;
private EntityManager entityManager;
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
public BaseJpaDao(Class<?> entityClass) {
this.entityClass = entityClass;
}
#Override
public E persist(E e) {
entityManager.persist(e);
return e;
}
I treid like this link
but not help.
I tried this
EntityManagerFactory emf = Persistence.createEntityManagerFactory("access", System.getProperties());
em = emf.createEntityManager();
but not help.
In Aries JPA 1.x that does not work.
In Aries JPA 2.x you can use exactly the same code as in spring. See TaskServiceImpl.java. You just need to add the jpa:enable and jta:enable elements to you blueprint context to activate the functionality.
Alternatively you can use the blueprint-maven-plugin to generate the whole blueprint.xml from annotations. Btw version 1.3.0 should be fine. You do not need the snapshot.
Thanks for the configuration snippets. The problem is that you use the wrong namespace for jpa. Try these:
xmlns:jpa="http://aries.apache.org/xmlns/jpa/v2.0.0"
xmlns:tx="http://aries.apache.org/xmlns/transactions/v1.2.0"
It seem like EntityManager is NOT flushing out the changes to the database. What makes this problem harder is that there is no exception thrown. I am using declarative transactions to define my transaction boundaries with the following flow:
SignUpController --> #Transactional: Tx.Start --> AccountServiceImpl.createAccount --> AccountDAOImpl.createAccount --> Tx.Commit --> SignUpController
From my investigation it seems like:
1.Spring is properly defining the Transaction Boundaries using #Transactional. Hence Transaction are being created
2.Also please Note the I am using the SharedEntityManagerBean, which means I CANNOT explicitly define my transaction boundaries e.g:
em.getTransaction().begin();
em.persist(entity);
em.getTransaction().commit();
The above code results in the following exception: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
Below is the relevant code and configuration. Any assistance will be greatly appreciated. Thanks.
MainConfig.java:
#Configuration
#ComponentScan(basePackages="com",excludeFilters= {#Filter(Configuration.class)})
#EnableTransactionManagement
public class MainConfig {
#Bean
public DataSource dataSource() {
DataSource ds = (DataSource)getFromInitialContext("java:jboss/datasources/PrimaryDB");
return ds;
}
#Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
#Bean
public EntityManagerFactory entityManagerFactory() {
EntityManagerFactory emf = (EntityManagerFactory) getFromInitialContext("java:jboss/entityManagerFactory");
return emf;
}
private Object getFromInitialContext(String jndiValue) {
Context ctx = null;
Object object = null;
try {
ctx = new InitialContext();
object = ctx.lookup(jndiValue);
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return object;
}
}
persistance.xml:
<persistence-unit name="PrimaryDB" transaction-type="JTA">
<jta-data-source>java:jboss/datasources/PrimaryDB</jta-data-source>
<class>com.domain.entities.Account</class>
<properties>
<!-- Bind entity manager factory to JNDI at java:jboss/myEntityManagerFactory -->
<property name="jboss.entity.manager.factory.jndi.name"
value="java:jboss/entityManagerFactory" />
<!-- Properties for Hibernate -->
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.use_sql_comments" value="true" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
</properties>
</persistence-unit>
AccountServiceImpl:
#Service
public class AccountServiceImpl implements AccountService {
#Inject
AccountDAO accountDAOImpl;
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public Account createAccount(SignupForm form, BindingResult formBinding) {
TransactionDebugUtil.transactionRequired("AccountServiceImpl.createAccount");
Account account =
new Account(form.getUsername(), form.getPassword(),form.getFirstName(), form.getLastName());
try {
accountDAOImpl.createAccount(account);
} catch (Exception ex) {
formBinding.rejectValue("username", "user.duplicateUsername",
"already in use: " + ex.getMessage());
return null;
}
return account;
}
}
AccountDAOImpl.java:
#Repository
public class AccountDAOImpl extends GenericJpaDAO<Account> implements AccountDAO {
#Override
#PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
entityManager.setFlushMode(FlushModeType.COMMIT);
}
#Override
public void createAccount(Account account) throws UsernameAlreadyInUseException {
entityManager.persist(account);
}
Hi the confusion was caused due to using annotations for configuring the transaction manager rather then XML.
Typical XML Configuration for SpringTransaction:
1.
<tx:annotation-driven />
^It scans all beans in the application context and creates AOP interceptor for those which are annotated.This is done via the SpringTransactionAnnotationParser, which is used by TransactionInterceptor.
#EnableTransactionManagement
^This is the equivalent configuration bean annotation to allow transactional support
2
. JTA datasource is defined in the persistence.xml. JBoss 7 automatically creates a JTA Transaction Manager and binds it to the following JNDI Location: java:/TransactionManager by default. This Transaction Manager is automatically discovered in spring with the following xml configuration:
<tx:jta-transaction-manager />
The equivalent annotation configuration for this is:
#Bean
public PlatformTransactionManager transactionManager() {
JtaTransactionManager txManager = new JtaTransactionManager();
return txManager;
}
This resolved my issue. Thanks #geoand for your help.
this kind of behaviour usually happens when we dont have #transactional
on the persistent method.
so add #Transactional on top of method like below
#Override
#Transactional
public void createAccount(Account account) throws UsernameAlreadyInUseException {
entityManager.persist(account);
}
You are not handling transaction management correctly. Replace your transaction manager bean with:
#Bean
public PlatformTransactionManager transactionManager() {
final JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
return txManager;
}
I need to inject EntityManager in EntityListener class so that I can perform CRUD operation on it.
POJO:
#Entity
#EntityListner(AuditLogging.class)
class User
{
//Getter / setter of properties
}
AuditLogging (Listner class)
public class AuditInterceptor
{
#PersistenceContext
EntityManager entityManager;
public void setEntityManager(EntityManager entityManager)
{
this.entityManager = entityManager;
}
#PrePersist
public void prePersist(Object obj)
{
// Here I want to use ENTITY manager object so that I can perform CRUD operation
// with prePersist coming object.
entityManager.unwrap(Session.class).save(obj);
// But I am getting NULL POINTER EXCEPTION for entity manager object
}
}
JDBC-CONFIg.xml
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
<property name="packagesToScan" value="com.XXXXX.entity" />
<property name="jpaProperties">
</bean>
<!-- Datasource -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${jdbc.driver.classname}" />
<property name="jdbcUrl" value="${jdbc.url}" />
</bean>
<!-- transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
EntityListener is not managed by any of the container.EntityListeners are instanciated by JPA, so Spring does not have an opportunity to inject EntityManager.
My question is, how we can inject inject EntityManager in EntityListener class so that I can perform CRUD operation on it ???
I have faced a similar problem where I was trying to create history records for an entity using EntityListeners.
In order to resolve this problem, I have created utility class BeanUtil with a static method to get the bean and used this util class to get bean inside my Entitylistener class
#Service
public class BeanUtil implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static <T> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
}
Now we can call BeanUtil.getBean() to get the bean of any type
public class FileEntityListener {
#PrePersist
public void prePersist(File target) {
perform(target, INSERTED);
}
#Transactional(MANDATORY)
private void perform(File target, Action action) {
EntityManager entityManager = BeanUtil.getBean(EntityManager.class);
entityManager.persist(new FileHistory(target, action));
}
}
We can use this BeanUtil class to get any spring managed bean from anywhere, To know more you can read my article JPA Auditing: Persisting Audit Logs Automatically using EntityListeners.
Anyways, I got this done by getting entityManager reference from EntityManagerFactory bean which is configured in my jdbc-config.xml. But again this is not what I wanted. I wanted to work around with #PersistenceContext.
#Autowired
EntityManagerFactory entityManagerFactory;
private static EntityManager entityManager;
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
entityManager=entityManagerFactory.createEntityManager();
this.entityManagerFactory = entityManagerFactory;
}
Here are few notes that we need to keep in mind:
We can't inject an EntityManager into an EntityListener (through
#PersistenceContext). EntityListener is not managed by any of the
containers
#PersistenceContext class cannot be static. So we cant
attain the instance while class loading.
EntityListeners are
instantiated by JPA, so Spring does not have an opportunity to
inject EntityManager
Well, the first solution which came into my mind is a little "hack", but should work.
public class AuditInterceptor {
static setEntityManager emf;
#Autowired
public void setEntityManagerFactory(EntityManager emf) {
AuditInterceptor.emf = emf;
}
#PrePersist
public void prePersist(Object obj) {
EntityManager entityManager = emf.getEntityManager();
// Here I want to use ENTITY manager object so that I can perform CRUD operation
// with prePersist coming object.
entityManager.unwrap(Session.class).save(obj);
// But I am getting NULL POINTER EXCEPTION for entity manager object
}
}
Inside of your code use EntityManager entityManager = emf.getEntityManager()
Declare your AuditInterceptor as a spring bean (#Component with component-scan or define AuditorInterceptor as a bean)
I used a ThreadLocal to pass the Spring Application Context which contains EntityManager around. Though I am not sure if it is safe Is it safe to pass in the Spring Application Context into a ThreadLocal associated with a request? but so far it is working for me.
The listener can be modified to have autowiring like this. However this needs to be done on on the handlers and not the constructor (doing it on the constructor seems less predictable). You are also not limited to the EntityManager but you have access to the whole context.
#Autowired
private EntityManager entityManager;
#Autowired
private MyDao myDao;
#PrePersist
public void pre() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
Objects.requireNotNull(myDao);
myDao.doSomething();
}
What is the best approach to get EntityManagerFactory in web app(jsp/servlets)?
Is this a good way When should EntityManagerFactory instance be created/opened?,
or is it better to get it from JNDI, or something else?
They're heavyweight and they're supposed to be in the application scope. So, you need to open them on application startup and close them on application shutdown.
How to do that depends on your target container. Does it support EJB 3.x (Glassfish, JBoss AS, etc)? If so, then you don't need to worry about opening/closing them (neither about transactions) at all if you just do the JPA job in EJBs with #PersistenceContext the usual way:
#Stateless
public class FooService {
#PersistenceContext
private EntityManager em;
public Foo find(Long id) {
return em.find(Foo.class, id);
}
// ...
}
If your target container doesn't support EJBs (e.g. Tomcat, Jetty, etc) and an EJB add-on like OpenEJB is also not an option for some reason, and you're thus manually fiddling with creating EntityManagers (and transactions) yourself, then your best bet is a ServletContextListener. Here's a basic kickoff example:
#WebListener
public class EMF implements ServletContextListener {
private static EntityManagerFactory emf;
#Override
public void contextInitialized(ServletContextEvent event) {
emf = Persistence.createEntityManagerFactory("unitname");
}
#Override
public void contextDestroyed(ServletContextEvent event) {
emf.close();
}
public static EntityManager createEntityManager() {
if (emf == null) {
throw new IllegalStateException("Context is not initialized yet.");
}
return emf.createEntityManager();
}
}
(note: before Servlet 3.0, this class needs to be registered by <listener> in web.xml instead of #WebListener)
Which can be used as:
EntityManager em = EMF.createEntityManager();
// ...
In my Spring+JPA/Hibernate+Wicket app, I have a QueryBuilder bean that I want to use in one of my DAOs which generates a typed query with the help of Criteria API:
#Service(value="inboxQueryBuilder")
public class InboxQueryBuilder {
#PersistenceContext
EntityManager em;
CriteriaBuilder cb;
public InboxQueryBuilder() {
cb = em.getCriteriaBuilder();
}
public TypedQuery<App> getQueryForApps(AppSearchObject aso) {
...
}
...
}
However, when I run the app, I get a null pointer exception for line:
cb = em.getCriteriaBuilder();
i.e. the EntityManager doesn't get injected. Do you know why?
Also, is this use correct and thread-safe or should I instantiate my InboxQueryBuilder for each query? In that case, should I also inject the EntityManager or should I just pass it as a constructor parameter (the InboxQueryBuilder would get instantiated for each query in the DAO which has an injected instance of EntityManager)?
You can't access the EntityManager within the constructor. Take a look at the #PostConstruct-Annotation
#Service(value="inboxQueryBuilder")
public class InboxQueryBuilder {
#PersistenceContext
EntityManager em;
CriteriaBuilder cb;
public InboxQueryBuilder() {
// em= null
}
#PostConstruct
public void toSomething(){
// em set by Container
cb = em.getCriteriaBuilder();
}
public TypedQuery<App> getQueryForApps(AppSearchObject aso) {
...
}
...
}
EDIT:
After reading your post again, I start to became unsure, if I'm right. I know the Java EE-Dependency-Injection within a JBoss works as I described, but I'm not sure about spring-IOC.
Do you have this bean somewhere in your application context?
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="myPersistenceUnit"/>
</bean>
Spring uses the Java Beans mechanism, so I am pretty sure this is insufficient:
#PersistenceContext
EntityManager em;
Here's the standard way:
private EntityManager entityManager;
#PersistenceContext
public void setEntityManager(final EntityManager entityManager){
this.entityManager = entityManager;
}