What does EntityManager::getDelegate return? - java

I am using JBoss 7 with the default Hibernate JPA engine in an EJB3 / JSF project.
The javadoc on EntityManager::getDelegate reads: "Return the underlying provider object for the EntityManager, if available.".
Out of curiosity I tried the following code:
#Stateless
public class AFacade {
#PersistenceContext(unitName="foo")
EntityManager em;
public List<A> findAll() {
l.info("underlying entity manager is: "+em.getDelegate().getClass().getSimpleName());
...
}
The output however indicates the classname as: org.hibernate.internal.SessionImpl which, according to hibernate documentation is a Session implementation.
What am I missing here ?

JPA is just a specification for ORM; there are some implementations for this specification/API the most known being Hibernate, EclipseLink, OpenJPA.
This means that the EntityManager is just an adapter to a class from the implementation library. In your case it is org.hibernate.internal.SessionImpl since you use Hibernate as a JPA implementation - this is the class that manages the code you give to the EntityManager.

Related

How does HibernateTemplate and Spring #Transactional work together?

We use HibernateTemplate in our DAOs for all the CRUD operations.
My question is, we use spring #Transactional on the services, Because the spring is managing the transactions, how does the HibernateTemplate behave in the senario where I update multiple DAOs. Meaning does HibernateTemplate use same session across different DAOs when Spring #Transactional is used?
#Transactional
public boolean testService(SObject test)[
dao1.save(test.getOne());
dao2.save(test.gettwo());
}
This is how the DAO class looks:
public class GenericHibernateDao<T, PK extends Serializable> extends HibernateDaoSupport
.
.
.
public PK save(T newInstance) {
return (PK) getHibernateTemplate().save(newInstance);
}
The HibernateTransactionManager javadoc is pretty clear about this:
This transaction manager is appropriate for applications that use a single Hibernate SessionFactory for transactional data access, but it also supports direct DataSource access within a transaction (i.e. plain JDBC code working with the same DataSource). This allows for mixing services which access Hibernate and services which use plain JDBC (without being aware of Hibernate)! Application code needs to stick to the same simple Connection lookup pattern as with org.springframework.jdbc.datasource.DataSourceTransactionManager (i.e. DataSourceUtils.getConnection or going through a TransactionAwareDataSourceProxy).
You're fine as long as you are accessing the connection through helper classes that are aware of the connection proxy such as DataSourceUtils (and the JdbcTemplate uses that behind the hood)

How to get entity manager or transaction in jpa listener

I was using Hibernate event listener like PostDeleteEventListener, PostInsertEventListener, PostUpdateEventListener to do some operations during insert, delete and update. Now I would like to use JPA listener to do this because if I like to move from Hibernate to any other JPA provider my listener should work. Hibernate listener gives me event from which I can get the transaction and check whether its committed or rollback. JPA listeners only provides me the entity object. Now how can I get the transaction or session or entity manger in the JPA listener?? Thanks in advance!! I am using Jboss as my CMT.
This is not supported as of JPA 2.0.
In JPA 2.1 (slated to be in Java EE 7), the persistence provider will treat entity listeners as CDI beans when in a managed environment (such as the JBoss app server). From the Proposed Final Draft of the JPA 2.1 spec, page 96:
Entity listener classes in Java EE environments support dependency
injection through the Contexts and Dependency Injection API (CDI) [ 10 ]
when the containing archive is a bean archive. An entity listener
class that makes use of CDI injection may also define lifecycle
callback methods annotated with the PostConstruct and PreDestroy
annotations. These methods will be invoked after injection has taken
place and before the entity listener instance is destroyed
respectively
So in JPA 2.1, if you create a CDI producer that provides EntityManager (simply by annotating a #PersistenceContext field with #Produces), you can just #Inject the EntityManager into the listener.
In the mean time, I'm not aware of any clean or pleasant workaround. The "least worst" thing I can think of would be to configure the EntityManager to be bound in JNDI, then obtain it through a JNDI lookup from within the listener.
In my case I'm using this code:
ApplicationContext ctx = ContextLoader.getCurrentWebApplicationContext();
auditLogService = (AuditLogService) ctx.getBean("auditLogService");
This works well to me.
The code of this application is available to download at https://bitbucket.org/macielbombonato/apolo
I hope that this can help you.
You can use all pre/post load, insert, update or delete listener in JPA by using two ways:
By using annotation.
An simple example of using a Listener could be where an entity has a transient variable that needs to be populated after the entity has been persisted, updated or loaded, like:
public class AvailableCreditListener {
#PostLoad
#PostPersist
#PostUpdate
public void calculateAvailableCredit(Account account) {
account.setAvailableCredit(
account.getBalance().add(
account.getOverdraftLimit()));
}
}
The entity class would be annotated with #EntityListeners:
#EntityListeners({AvailableCreditListener.class})
public class Account extends BaseEntity {
private BigDecimal balance;
private BigDecimal overdraftLimit;
#Transient
private BigDecimal availableCredit;
// getters and setters
}
By using persistence.xml configuration file.
Finally, instead of annotations, an XMl mapping file can be used and deployed with the application to specify default listeners. (This mapping file is referenced by the persistence.xml file.) But an entity can use the #ExcludeDefaultListeners annotation if it does not want to use the default listeners.
#ExcludeDefaultListeners
#Entity
public class Account extends BaseEntity {
....
}
In your persistence.xml:
<persistence-unit-metadata>
<persistence-unit-defaults>
<entity-listeners>
<entity-listener class="samples.AvailableCreditListener"/>
</entity-listeners>
</persistence-unit-defaults>
</persistence-unit-metadata>

Service methods without using hibernate template

I have been googling for several hour now trying to find an example on how to write a service method that doesn't use Springs Hibernate Template while using a DAO interface. Something that is also confusing me is what happens when I put the #Transactional annotation in the service layer as opposed the DAO. Are the Service methods/DAO interfaces interchangeable?
Here is an example where the #Transactional is in the DAO
Here is one with the #Transactional in the Service Layer but using hibernate templates
Thanks for your help!
The Spring documentation recommends avoiding HibernateTemplate completely, and use the Hibernate API directly instead:
NOTE: As of Hibernate 3.0.1, transactional Hibernate access code can
also be coded in plain Hibernate style. Hence, for newly started
projects, consider adopting the standard Hibernate3 style of coding
data access objects instead, based on
SessionFactory.getCurrentSession().
And the #Transactional annotation should always be put on methods of the service layer. This is the layer that demarcates transactions.
Read http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#orm-session-factory-setup to understand how to setup a session factory. Once done, the session factory can be injected in your DAOs:
#Repository
public class MyDAO {
#Autowired
private SessionFactory sessionFactory;
...
}

How to use Eclipselink #Multitenant in JSF/EJB?

The #Multitenant support in Eclipselink 2.3 looks really interesting, but I'm having a hard time understanding how to use it in a JSF or EJB which injects an EntityManager with #PersistenceContext. The EclipseLink docs are pretty clear that #PersistenceContext injection doesn't work in this case, but you could inject an EntityManagerFactory via #PersistenceUunit instead.
Still, what I'm not seeing is how to manage the lifecycle of an EntityManager you might create via injected EntityManagerFactory.createEntityManager() - in particular, when to close the resulting EntityManager, and how to participate in transactions.
Has anyone gotten this to work? Or am I missing something obvious?
See also: http://wiki.eclipse.org/EclipseLink/Examples/JPA/Multitenant
UPDATE
I had some success with #PersistenceContext (EntityManager) injection and then passing parameters to EclipseLink via session listener. I'm not 100% sure this is the right answer and would appreciate confirmation that it isn't creating a non-obvious race condition or thread-safety issue.
For example:
public static class TenantListener extends SessionEventAdapter {
#Override
public void postAcquireClientSession(SessionEvent event) {
long tenantId = **business logic**;
event.getSession().setProperty("eclipselink.tenant-id", tenantId);
}
}
Using events is fine.
You could also inject the EntityManager and set the property, or inject the EntityManagerFactory and use joinTransaction() to join the active JTA transaction.

Hibernate SessionFactory vs. JPA EntityManagerFactory

I am new to Hibernate and I'm not sure whether to use a Hibernate SessionFactory or a JPA EntityManagerFactory to create a Hibernate Session.
What is the difference between these two? What are the pros & cons of using each of those?
Prefer EntityManagerFactory and EntityManager. They are defined by the JPA standard.
SessionFactory and Session are hibernate-specific. The EntityManager invokes the hibernate session under the hood. And if you need some specific features that are not available in the EntityManager, you can obtain the session by calling:
Session session = entityManager.unwrap(Session.class);
SessionFactory vs. EntityManagerFactory
As I explained in the Hibernate User Guide, the Hibernate SessionFactory extends the JPA EntityManagerFactory, as illustrated by the following diagram:
So, the SessionFactory is also a JPA EntityManagerFactory.
Both the SessionFactory and the EntityManagerFactory contain the entity mapping metadata and allow you to create a Hibernate Session or a EntityManager.
Session vs. EntityManager
Just like the SessionFactory and EntityManagerFactory, the Hibernate Session extends the JPA EntityManager. So, all methods defined by the EntityManager are available in the Hibernate Session.
The Session and the `EntityManager translate entity state transitions into SQL statements, like SELECT, INSERT, UPDATE, and DELETE.
Hibernate vs. JPA bootstrap
When bootstrapping a JPA or Hibernate application, you have two choices:
You can bootstrap via the Hibernate native mechanism, and create a SessionFactory via the BootstrapServiceRegistryBuilder. If you're using Spring, the Hibernate bootstrap is done via the LocalSessionFactoryBean, as illustrated by this GitHub example.
Or, you can create a JPA EntityManagerFactory via the Persistence class or the EntityManagerFactoryBuilder. If you're using Spring, the JPA bootstrap is done via the LocalContainerEntityManagerFactoryBean, as illustrated by this GitHub example.
Bootstrapping via JPA is to be preferred. That's because the JPA FlushModeType.AUTO is a much better choice than the legacy FlushMode.AUTO, which breaks read-your-writes consistency for native SQL queries.
Unwrapping JPA to Hibernate
Also, if you bootstrap via JPA, and you have injected the EntityManagerFactory via the #PersistenceUnit annotation:
#PersistenceUnit
private EntityManagerFactory entityManagerFactory;
You can easily get access to the underlying Sessionfactory using the unwrap method:
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
The same can be done with the JPA EntityManager. If you inject the EntityManager via the #PersistenceContext annotation:
#PersistenceContext
private EntityManager entityManager;
You can easily get access to the underlying Session using the unwrap method:
Session session = entityManager.unwrap(Session.class);
Conclusion
So, you should bootstrap via JPA, use the EntityManagerFactory and EntityManager, and only unwrap those to their associated Hibernate interfaces when you want to get access to some Hibernate-specific methods that are not available in JPA, like fetching the entity via its natural identifier.
I want to add on this that you can also get Hibernate's session by calling getDelegate() method from EntityManager.
ex:
Session session = (Session) entityManager.getDelegate();
I prefer the JPA2 EntityManager API over SessionFactory, because it feels more modern. One simple example:
JPA:
#PersistenceContext
EntityManager entityManager;
public List<MyEntity> findSomeApples() {
return entityManager
.createQuery("from MyEntity where apples=7", MyEntity.class)
.getResultList();
}
SessionFactory:
#Autowired
SessionFactory sessionFactory;
public List<MyEntity> findSomeApples() {
Session session = sessionFactory.getCurrentSession();
List<?> result = session.createQuery("from MyEntity where apples=7")
.list();
#SuppressWarnings("unchecked")
List<MyEntity> resultCasted = (List<MyEntity>) result;
return resultCasted;
}
I think it's clear that the first one looks cleaner and is also easier to test because EntityManager can be easily mocked.
Using EntityManagerFactory approach allows us to use callback method annotations like #PrePersist, #PostPersist,#PreUpdate with no extra configuration.
Using similar callbacks while using SessionFactory will require extra efforts.
Related Hibernate docs can be found here and here.
Related SOF Question and Spring Forum discussion
By using EntityManager, code is no longer tightly coupled with hibernate. But for this, in usage we should use :
javax.persistence.EntityManager
instead of
org.hibernate.ejb.HibernateEntityManager
Similarly, for EntityManagerFactory, use javax interface. That way, the code is loosely coupled. If there is a better JPA 2 implementation than hibernate, switching would be easy. In extreme case, we could type cast to HibernateEntityManager.
EntityManagerFactory is the standard implementation, it is the same across all the implementations. If you migrate your ORM for any other provider like EclipseLink, there will not be any change in the approach for handling the transaction. In contrast, if you use hibernate’s session factory, it is tied to hibernate APIs and cannot migrate to new vendor.
EntityManager interface is similar to sessionFactory in hibernate.
EntityManager under javax.persistance package but session and sessionFactory under org.hibernate.Session/sessionFactory package.
Entity manager is JPA specific and session/sessionFactory are hibernate specific.

Categories

Resources