I am new in Spring Boot and trying to create a basic REST example in Spring boot. I am taking help from Spring Boot REST example website to create a basic example.
Most of the things are clear to me but I am stuck with one annotation which is being used to fetch the data from the database with the code as below
package com.springbootrest.repository;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import org.springframework.stereotype.Repository;
import com.springbootrest.model.BookDetails;
#Transactional
#Repository
public class BookDetailsRepoImpl implements BookDetailsRepo {
#PersistenceContext
private EntityManager entityManager;
public List<BookDetails> listBookDetails() {
return (List<BookDetails>) entityManager.createQuery("FROM BookDetails").getResultList();
}
}
I don't understand how #PersistenceContext is actually working - can anyone please explain?.
#PersistenceContext – We need to understand how we are able to connect with the database using just simple annotation #PersistenceContext and what it is.
Entities are managed by javax.persistence.EntityManager instance
using persistence context.
Each EntityManager instance is associated with a persistence
context.
Within the persistence context, the entity instances and their
lifecycle are managed.
Persistence context defines a scope under which particular entity
instances are created, persisted, and removed.
A persistence context is like a cache which contains a set of
persistent entities , So once the transaction is finished, all
persistent objects are detached from the EntityManager’s persistence
context and are no longer managed.
The #PersistenceContext annotation in your code is being used to indicate that the EntityManager must be automatically injected, in other words its lifecycle will be managed by the container running your application (which is a good thing). The other option would be having all required configurations provided by you (application managed) via different options, all of them cumbersome (config files or beans) and running the risk of tying your application to some environment-specific configuration (which is a bad thing).
#PersistenceContext is JPA standard annotation which gives you better control of which persistence context you are Injecting.
My answer comes after quite a few years but here goes .
this annotation #PersistentContext works in conjunction with another bean defined in your application context:
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
The way the two work together is that the PersistenceAnnotationBeanPostProcessor will lookup the appropriate EntityManagerFactory to inject the entity manager where we have attributes annotated with #PersistenceContext
My understanding is based on the answers to this question: so question here
In Short or layman language, Its a space(just to say) where entities are managed using Entity Manager.
Related
Is it possible to inject beans to a JPA #Entity using Spring's dependency injection?
I attempted to #Autowire ServletContext but, while the server did start successfully, I received a NullPointerException when trying to access the bean property.
#Autowired
#Transient
ServletContext servletContext;
You can inject dependencies into objects not managed by the Spring container using #Configurable as explained here: http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/aop.html#aop-atconfigurable.
As you've realized by now, unless using the #Configurable and appropriate AspectJ weaving configuration, Spring does not inject dependencies into objects created using the new operator. In fact, it doesn't inject dependencies into objects unless you've retrieved them from the ApplicationContext, for the simple reason that it simply doesn't know about their existence. Even if you annotate your entity with #Component, instantiation of that entity will still be performed by a new operation, either by you or a framework such as Hibernate. Remember, annotations are just metadata: if no one interprets that metadata, it does not add any behaviour or have any impact on a running program.
All that being said, I strongly advise against injecting a ServletContext into an entity. Entities are part of your domain model and should be decoupled from any delivery mechanism, such as a Servlet-based web delivery layer. How will you use that entity when it's accessed by a command-line client or something else not involving a ServletContext? You should extract the necessary data from that ServletContext and pass it through traditional method arguments to your entity. You will achieve a much better design through this approach.
Yes, of course you can. You just need to make sure the entity is also registered as a Spring managed bean either declaratively using <bean> tags (in some spring-context.xml) or through annotations as shown below.
Using annotations, you can either mark your entities with #Component (or a more specific stereotype #Repository which enables automatic exception translation for DAOs and may or may not interfere with JPA).
#Entity
#Component
public class MyJAPEntity {
#Autowired
#Transient
ServletContext servletContext;
...
}
Once you've done that for your entities you need to configure their package (or some ancestor package) for being scanned by Spring so that the entities get picked up as beans and their dependencies get auto wired.
<beans ... xmlns:context="..." >
...
<context:component-scan base-package="pkg.of.your.jpa.entities" />
<beans>
EDIT : (what finally worked and why)
Making the ServletContext static. (remove #Autowired)
#Transient
private static ServletContext servletContext;
Since, JPA is creating a separate entity instance i.e. not using the Spring managed bean, it's required for the context to be shared.
Adding a #PostConstruct init() method.
#PostConstruct
public void init() {
log.info("Initializing ServletContext as [" +
MyJPAEntity.servletContext + "]");
}
This fires init() once the Entity has been instantiated and by referencing ServletContext inside, it forces the injection on the static property if not injected already.
Moving #Autowired to an instance method but setting the static field inside.
#Autowired
public void setServletContext(ServletContext servletContext) {
MyJPAEntity.servletContext = servletContext;
}
Quoting my last comment below to answer why do we have to employ these shenanigans:
There's no pretty way of doing what you want since JPA doesn't use the Spring container to instantiate its entities. Think of JPA as a separate ORM container that instantiates and manages the lifecycle of entities (completely separate from Spring) and does DI based on entity relationships only.
After a long time I stumbled across this SO answer that made me think of an elegant solution:
Add to your entities all the #Transient #Autowired fields you need
Make a #Repository DAO with this autowired field:
#Autowired private AutowireCapableBeanFactory autowirer;
From your DAO, after fetching the entity from DB, call this autowiring code:
String beanName = fetchedEntity.getClass().getSimpleName();
autowirer.autowireBean(fetchedEntity);
fetchedEntity = (FetchedEntity) autowirer.initializeBean(fetchedEntity, beanName);
Your entity will then be able to access the autowired fields as any #Component can.
I'm developing an application, and I started with creating my JPA entities (annotation + persistence.xml). Then in my persistence.xml file, I created a connection for a MySql data base (the connection is fine).
The problem is that I just don't know how to persist my entities without creating a "main class".
Do I have to run my main class for every single entity that I'm going to create?
To persist an entity, you need an instance of entityManager. Since you have a Java EE container you can get an instance of entityManager using the annotation #PersistenceContext in some bean
What I mean by some bean ? It's a bean managed by the Java EE container. So, for instance you have to define a bean like this :
#Stateless
public class MyController{
#PersistenceContext
private EntityManager em;
public void persistIt(Object anEntity){
em.persist(anEntity);
}
}
The annotation #Stateless indicate to the container that it must manage this class and take care of providing an instance of the entityManager when needed.
So to answer precisely to your question: it is not mandatory to have another class to persist an entity, as soon as you find a way to get access to an entityManager instance.
But:
it is definitively NOT a best practice.
to take advantages of entityManager injection: you must use another managed bean so that entityManager can be injected by the container.
Additionally, the controller is where you can handle your transactions properly.
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>
I am developing a JavaEE6 based web application using JBoss7.
In my application I am injecting the EntityManager in my EJBs as:
class ForumServiceEJB
{
#PersistenceContext(type=EXTENDED)
private EntityManager em;
}
class TopicServiceEJB
{
#PersistenceContext(type=EXTENDED)
private EntityManager em;
}
The problem when I update some data using ForumServiceEJB's EntityManager then the changes are made into DB but TopicServiceEJB's EntityManager is not able to see those changes and the results are always fetched from Cache.
I am using ExtendedPerssisteenceContext as My Entities contain child Entity Collections of Lazy Loading type.
How can I use/Inject EntityManager of type ExtendedPersistenceContext and make different EntityManager in one EJB can still see the changes done by other different EJB EntityManagers?
Somewhere I read EntityManagers should be RequestScoped objects.
public class MyEntityManagerProducers {
#Produces #RequestScoped
public EntityManager createDbEm() {
return Persistence.createEntityManagerFactory("forumDb").
createEntityManager();
}
public void disposeUdEm(#Disposes EntityManager em) {
em.close();
}
Is it the way to go?
I am using ExtendedPerssisteenceContext as My Entities contain child
Entity Collections of Lazy Loading type.
This is not a good reason to use EXTENDED. I would suggest you to make it default, which is TRANSACTION. And it's good to make your EntityManager request-scoped, or method-scoped, in non-enterprise environment or when using application-managed persistence, as this is not a very heavy object to create. Moreover, neither using application-scoped EntityManager is a good idea, as it is not threadsafe.
Having said that, as you are using JBoss, you should let the container handle the lifecycle of EntityManager, in case you are using JTA. Hence, just inject that with everything default
Note:
Only stateful session beans can have a container-managed, extended entity manager.
Links:
http://javanotepad.blogspot.com/2007/08/managing-jpa-entitymanager-lifecycle.html
https://blogs.oracle.com/enterprisetechtips/entry/extended_persistence_context_in_stateful
Suggestions:
Your business method should know whether to load the children or not. But that's the ideal case. A number of times we can't say that and completely depends on the user input -- we can't predict that well. Therefore, there are two solutions available,
make a separate AJAX call to load children
Use the filter called open-session-in-view. I would prefer the former.
Links:
https://community.jboss.org/wiki/OpenSessionInView
http://static.springsource.org/spring/docs/1.2.9/api/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.html
Why is Hibernate Open Session in View considered a bad practice?
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;
...
}