I am getting a LIE when using the JAX-WS #Path and the #Stateless (or #RequestScoped) annotation. The code:
#Path("/users")
#Stateless
#Produces(MediaType.APPLICATION_XML)
public class UserResourceRESTService {
#Inject
#UserRepository
#PersistenceContext
private EntityManager em;
#GET
#Path("/{id:[1-9][0-9]*}")
public User lookupUserById(#PathParam("id") long id) {
return em.find(User.class, id);
}
}
The actual exception I am getting:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
The user object has an address, which has a country. If I change this to a stateful bean and use an extended context it works, but this really shouldn't be a SFSB should it? I am at a bit of a loss as to why the "em" wouldn't be able to open a session when using a stateless bean?
When you are operating in extended persistence context your returned User entity remains in managed state and when you are using transaction persistence context transaction ends once lookupUserById() method returns and result of that method is an entity which is already detached from persistence context. As a result all properties of that entity which are marked as LAZY are not accessible anymore.
If you want to access these lazy properties after entity became detached from persistence context invoke specific getter methods on that entity prior returning from lookupUserById method.
i.e.
public User lookupUserById(#PathParam("id") long id) {
User user = em.find(User.class, id);
user.getAddress().getCountry();
return user;
}
You can also annotate your relationships in User class with fetch = FetchType.EAGER. If you always return everything it's no point to have lazy loading in my opinion.
Related
I have following logic:
ModelEntity savedModelEntity = modelEntityRepository.save(modelEntityForSave);
//saving collection to entity here
ModelEventEntity modelEventEntity = prepareModelEventEntityForSave(savedModelEntity);
modelEventRepository.save(modelEventEntity);
//this modelEntity is cached
ModelEntity modelEntity = modelEntityRepository.findById(savedModelEntity.getId());
How can I disable hibernate caching for this entity only in this place?
findById of the JpaRepository uses EntityManger.find() that will return the entity from the Persistence Context.
Unfortunately the JpaRepository does not expose EntityManager.refresh that you need to use.
So you may use the EntityManager directly and refresh the Entity.
// Inject the EntityManager
#Autowired
private EntityManager em;
// Refresh the Entity
em.refresh(savedModelEntity);
You can add annoation to your repository:
#Modifying(clearAutomatically = true)
That way, we make sure that the persistence context is cleared after our query execution.
or
#Modifying(flushAutomatically = true)
Now, the EntityManager is flushed before our query is executed.
I have a Project entity with a oneToMany relationship with Event entity
public class Project {
....
#OneToMany(mappedBy = "dossier", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Event> events;
}
I have a ProjectService class
#Service
#Transactional
public class ProjectService {
public List<Project> findAll() {
return (List<Project>) projectRepository.findAll();
}
}
And a ProjectController
#RestController
#RequestMapping(value = "/projects")
public class ProjectController {
#RequestMapping(method= RequestMethod.GET)
public List<Project> getAllProject() {
return projectService.findAll();
}
}
In my client code I saw that the events of the projects are loaded and I don't understand why.
I expected that at the end of the transaction of the method findAll in DossierService, the entities will be detached. Obviously my entities are still attached as the events are retrieved during the jackson serialization in my controller.
Project.events is by default lazy-loaded because it is a OneToMany relationship.
It does not mean that Project.events is not loaded. It means that it will be loaded as soon as Project.getEvents() is called.
This occurs at the JSON serialization (when ProjectController.getAllProject() returns its response).
In order to prevent that, there are 2 ways :
Either you explicitly call project.setEvents(null) (or an empty list) on every project returned by ProjectService.
Or you add a #JsonIgnore annotation on Project.events.
EDIT: if you are using spring-boot, an OpenEntityManagerInViewInterceptor is registered by default :
Spring web request interceptor that binds a JPA EntityManager to the thread for the entire processing of the request. Intended for the "Open EntityManager in View" pattern, i.e. to allow for lazy loading in web views despite the original transactions already being completed.
You can disable this behavior by adding this line to application.properties :
spring.jpa.open-in-view=false
With this configuration, calling the getter outside of the hibernate session will cause a LazyInitializationException.
There are two possibilities:
An OpenSessionInView or OpenEntityManagerInView bean has been defined. This type of bean causes the Session or EntityManager, respectively, to be opened at the time the controller is invoked and remains open until the controller's body has been serialized.
It is typically considered acceptable behavior in demo/small applications, but it's highly frowned upon in larger more complex applications as your queries should return fully initialized entities required for your view, controller, or logic.
The JSON library has a hibernate addon enabled where it is capable of reattaching and hydrating the entity during the serialization process.
Otherwise, the default behavior that you expect where the Session/EntityManager has closed and the entity is detached once it's returned by the service is accurate. The expected behavior would be a LazyInitializationException otherwise.
Your entities are still attached until:
You ask the entity manager to clear the persistence context using entityManager.clear()
You ask the entity manager to detach your entity using entityManager.detach(project) for every project.
But if you know that your events will be loaded most of the time, you should then consider using FetchType.EAGER so that everything would be fetched at once.
First of all I am new to JPA and Jax-rs, i am trying to develop a rest service. So i have created a resource class and annotated it.
#Path("/companies")
public class CompanyResource {
private EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("test");
#GET
#Produces({MediaType.APPLICATION_JSON})
public List<Company> getCompanies() {
EntityManager entityManager = entityManagerFactory.createEntityManager();
return new ArrayList<>();
}
#GET
#Path("{companyId}")
#Produces({MediaType.APPLICATION_JSON})
public Company getCompany(#PathParam("companyId") int id) {
return new Company();
}
}
From what i have understood about jax-rs for every client request instance of CompanyResource will be created, that means every time new EntityManagerFactory will be created, which i guess is not a good idea, as i just need it to create entity managers, which could be done with only one instance of it. So what is a proper way to achieve this? Or is it ok to create new instance of this factory for every request?
P.S. i have seen some examples where they use #Stateless annotation and inject Entity Manager, but i guess they use EJB there(i might be wrong) and i don't want to deep into EJB right now.
I think you should inject the entitymanager itself (not the factory), and let the container take care of instantiation and scopes. What we usually do is something like
#Stateless
#Path("services")
public class MyServices {
#PersistenceContext
private EntityManager em;
// ...
apart from the #Stateless (which imho you should use, there's no need to get deep into EJB for this), it's actually quite simple.
I have a huge object(entity) that stores some vertexes and edges on it.I want to store this entity in server to access every time I want. I will make some algorithms on it, So I do not want to load it from database every time. So I want it to be attached to Entity Manager until I detach. Of course I can open another entity , then old entity will be datached from entity manager, newly persisted entity will be detached.
I am using container managed bean. As you know, I could not control transactions over container managed beans.
I have defined a Singeton bean and define this entity as an attribute inside it. As I understand, when I lookup bean every time, a new transaction is started, So entity manager does not contain my entity in persistence context. So entity manager tries to do so many select statements to attach object to persistence context. If I use Hibernate Session, entity is attached to session until I call session.close(). How can I do this using entity manager?
#Singleton
public class BEan implements BEanRemote {
#PersistenceContext(unitName = "DBService")
private EntityManager em;
// ** newly opened entity.*/
private Entity entity;
}
After constructing the bean, I want to retrieve data from the database, using the EntityManager. It is not possible in the constructor, because the EntityManager is injected after the constructor is called. So I tried to do it in a method annotated with #PostConstruct. According to the API, a PostConstruct Methods gets called after all injection are done. Executing the query works, but it always returns an empty list. If I use the same query in an other method, it returns the correct result. Does anybody know, why it does not work in the PostConstruct method?
#Stateful(mappedName = "price")
#Singleton
#Startup
public class PriceManagementBean implements PriceManagement {
#PersistenceContext
private EntityManager em;
private List<PriceStep> priceSteps = Collections.synchronizedList(new ArrayList<PriceStep>());
public PriceManagementBean(){
}
#PostConstruct
public void init(){
javax.persistence.Query query = em.createQuery("SELECT ps FROM PriceStep ps");
List<PriceStep> res = query.getResultList();
.....
}
}
Does anybody know, why it does not work in the PostConstruct method?
Reason 1
You cannot create a bean that is at the same time #Stateful and #Singleton(Well you can but it will make no sense since Singletons are also Stateful), that is one of the reasons you are having trouble. There is no exceptions, but there is a conflict in there, you need to fix that first.
Just remember:
A Singleton bean is a bean that mantains its state. There is only one instance of a Singleton in an application and it is shared among all the users of the app. Also since it is a shared(maybe better say concurrent) bean, there is need to implement some kind of locking mechanism using the #Lock annotation.
A Stateful bean is a bean that mantains each state after a transaction. When working with
Stateful beans each user gets a copy of the bean which will last as long as the session - lasts or until a method annotated with #Remove is called
Reason 2
Even if it works, you will be unable to access the results, because you are storing them in an object called res which is only accessible from inside the method init(). I suppose you would like to assign that returned value to the variable priceSteps.
Anyway there are many things wrong in your code, for not saying everything. I don't know what are your system requirements, but here i would give you a simple solution that will allow you to access the database:
I suppose you are trying to in some way return the data in the life cycle of the bean because you want to avoid sending queries again and again if the bean is #Stateful.
The thing is, you don't have to do that, you can still make your bean #Stateless and avoid stressing your database with many queries.
What you need to do is create a #NamedQuery.
So annotate your entity PriceStep with #NamedQuery and there enter the query string you wrote. In this link you will find information about how to use #NamedQueries:
http://docs.oracle.com/cd/B31017_01/web.1013/b28221/ent30qry001.htm
The next thing i would suggest you is to annotate your class PriceManagementBean as *#Stateless*. Don't worry if in each request a new entityManager is created, that does not stress the database at all, because it interacts with the domain model.
You don't need #PostConstruct, you just call your #NamedQuery whenever you need it and that's it. The app server will cache it and give it back to each user that requires it without interacting with the database all time.
Here a codesnipet:
#Entity
#NamedQuery(
name="allPriceSteps",
queryString="SELECT ps FROM PriceStep ps"
)
public class PriceStep implements Serializable {
...
}
Now the bean:
#Stateless
public class PriceManagementBean implements PriceManagement {
#PersistenceContext
private EntityManager em;
public List<PriceStep> getAllPriceSteps() {
Query query = em.createNamedQuery("allPriceSteps");
return query.getResultList();
}
}
I hope this is useful. If you give more information about your system requirements we could give you advice on a best practice.
Based on your requirement please try the following
Remove #Stateful [CAN'T use both at a time]
#Startup will initialize singleton bean during APPLICATION INIT [Please note the application was NOT fully initialized]. This might caused some issue in loading EntityManager and i assume the EntityManager bridge was not completely initialized. Try to call the init after complete application startup [i.e.,] Remove #Startup