Can not wire service in entity - java

I've got an entity class and few services. That works well. But now I want to use a service inside an entity. I've added #Configurable and #Transient annotation to entity class and also <context:spring-configured /> statement to root-context.xml. Console says:
java.lang.NullPointerException
I've checked if service field is null and yes, it is. What is wrong?

Entities are not Spring beans. Spring doesn't know about them, and is not responsible for their instantiation. It thus can't inject anything into them.
Calling a service from an entity is just not something you should do. The service layer uses the domain layer, but not vice-versa.

Related

Can we use #autowired on an entity object in spring?

I have a entity class called Customer, I am using this entity object in another class to set the data. When I use this object below like
#Autowired
Customer customer
Spring is complaining that please configure the bean in your classes.
Can we use auto wiring with entity objects?
You can only autowire only those beans whose life-cycle are managed by Spring IoC container.
These beans are defined in xml form with </bean> tag, or with some special annotations like #Bean, #Component, #Service, #Repository etc.
On the other hand,
in simple terms, entities are some java objects that you will need to create, update by yourself according to your business logic and save/update/remove them in/from DB. Their life-cycle cannot be managed by Spring IoC container.
So, you should never feel like you need to autowire an entity if you are doing it right!
In fact, Spring support #Autowire only for Spring Beans. A java class becomes Spring Bean only when it is created by Spring, otherwise it is not.
A workaround might be to annotate your class with #Configurable but you would have to use AspectJ
Please look in the Spring documentations on how to use #Configurable
Also, I wonder why you would autowire an entity class ?
I would warn you not to mix Spring Bean and JPA entities in one class/usecase because:
Spring Beans are instantiated and managed by Spring
Entities are managed by JPA provider
If you mean JPAs #Entity-annotation, Spring is simply telling you, that there isn't a bean in its context.
On startup/runtime classes in the application will be scanned and each class annotated with spring annotations like #Component, #Service etc. will be instantiated as beans and put into a global context (Spring applicationcontext).
This context is then used to lookup and inject those beans into other beans when #Autowired is found during scanning.
Opposed to this, #Entity is used during the creation of the Persistence-Context of JPA (as far as I remember) which isn't aware of Spring and it's context.
Most of the solutions to make both contexts aware of each other a mostly a little bit hacky.

differences between JPA #EntityListeners , #PrePersist and Spring #RepositoryEventHandler, #HandleBeforeSave

I did some research but was not able to find what is a differences between
JPA #EntityListeners , #PrePersist
and
Spring #RepositoryEventHandler, #HandleBeforeSave
Thanks.
#HandleBeforeSave only works when an Entity is saved through a Spring Data repository. #PrePersist will be trigger if you use EntityManager::persist() and if you use JPARepository::save(), since it calls persist.
The nice thing with #RepositoryEventHandler+#HandleBeforeSaveis that your #HandleBeforeSave method is defined inside a spring bean, so you can interact with other spring beans. #EntityListeners and #PrePersist can only access the state of the current Entity when operating in a J2SE environment. In J2EE you can #Inject beans into a #EntityListeners because the JPA subsystem and CDI are both managed by the same Container.
Actually after more searching I found this answer
stackoverflow.com/a/31155291/1780517
It seems that there is also one VERY BIG different, #HandleBeforeSave called on Controller POST method and not on repository save.
So #RepositoryEventHandler should be used only if you want handle events from controller (PUT, POST, GET with#HandleBeforeSave, #HandleBeforeCreate ..) and #EntityListeners should be used for repository method save,delete, update with #PreUpdate , #PreRemove and so on..

Lazy loading working in non-transactional class/method in Hibernate

I am working in Spring-Hibernate application. Flow is as usual: Controller --> Service --> DAO.
I have annotated Service layer class with #Transactional, thereby marking every method transactional in that class.In service class, I made a DAO call to get some domain object and then converting it into DTO/VO object which will be passed to controller.For converting domain object to DTO, I have written another custom static class(class having only static methods) like ObjectMapper which will do this conversion.
Now, domain object has some child object(One to Many) which is lazily loaded. So, when in ObjectMapper, i access that child getter method, an extra database call is issued, which is working fine.
What I don't understand is that since ObjectMapper is not transactional, I was expecting some exception to be thrown like Session is closed while making database call to fetch child object from database.I am using getCurrentSession of Session Factory in DAO.
Can someone please explain me this behavior?
I suppose you either call your ObjectMapper from the transactional Service method (you should) or if not, maybe you are enabled "hibernate.enable_lazy_load_no_trans" which keeps the hibernate session open
As long as the call to the static class/method, which transforms your objects, is made in the transactional method of the DAO, the session is still open and will be used for the database calls.

DAO class instance vs DAO EJB

What is the best practice in java EE?
Create an instance of the DAO class in the service (or manager) class
SalesDAO salesDao = new SalesDAOImpl();
salesDao.findCustomers();
or
Call a DAO EJB in the service (or manager) class
#EJB
private SalesDAO salesDao;
salesDao.findCustomers();
The second one is the best practice (your DAO could be a CDI bean: it doesn't have to be an EJB).
Dependency injection is what makes the code testable: you can inject a mock DAO in the service when unit-testing the service.
BTW, the DAO will also need to have a DataSource or an EntityManager injected to be able to get data from the database. This is only possible if the DAO instance is managed by the container.
I preffer the second one.
DAO talks about responsability, means manage persistent data. But there is no reason for not to use a EJB. Let the container manage instances for you.
Adam Bien, member of EJB 3.1 spec comitee said in his blog:
http://www.adam-bien.com/roller/abien/entry/generic_crud_service_aka_dao

Seeking a Spring (3.0.5) Solution for: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

I have a Transaction problem on Spring 3.0.5. In my case I get the so-called exception "No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here"... I have tried everything so far. I can see in my log that the transactional services are detected and registered as Spring beans and I can also see in the logs that they are proxied and associated with underlying Spring transaction interceptors. (Advise) When I run my Spring MVC app my controller will call the service...... :-( but the transaction interceptors are not triggered. (??) I expect my Spring service proxy to open a session and start a transaction before calling my target service method. Since this does not happen, I get the above exception. I have been almost two days on this problem. Tried everything which I found on the internet...but in vain.
I have layered architecture: presentation (springmvc), service (transaction annotated), dataacess (Spring/Hibernate classic sessionfactory). My model objects are annotated with jpa (javax.persistence.*). My spring context config files are separated in appContext.xml, appContext-service.xml and appContext-dao.xml. I have defined my Spring LocalSessionFactoryBean, Datasource and TransactionManager (HibernateTransactionManager) in appContext-dao.xml. I have put in appContext-service.xml where my service implementations resides. In all of my config files I have included and to detect my beans through Controller, Service and Repository annotations.
I appreciate any kind of help.
It sounds like you are doing everything correctly and you know what you are doing. There's not much we can do here unless you show some configuration.
What I'd suggest is some debugging.
First: do you have Unit tests in the service layer that test the queries you are using? Perhaps you can find the error in the service layer.
Then: debug the MVC app, check the types of the injected services. Verify that they are proxies, not the original types.
If they are the original types, you
have an error in your transaction
configuration .
If they are proxies, step through the
query methods and verify that the
transaction logic is applied.
This sounds like accessing a lazily-loaded list or set of you dao after the closing of the transaction. This typically happens if you access that list in the view in stead of the controller, as your controller probably calls methods in transaction scope, and then leaves the transaction and forwards the loaded bean to the view.
Simple solutions:
Configure your data bean to eagerly load
Force loading of the dependencies in the controller (just loop through them)
have a look at this article ans possibly also quite a few right here on SO on lazy loading / lazy fetching of one-to-many associations and the like
Imagine:
// your dao
public class Foo {
// lots of other properties
List<Something> stuff;
// getters and setter for stuff
}
// repository
#Transactional
public class FooRepo {
public Foo loadFoo(int id) {
...
}
}
// Controller
public class Controller {
public void Control() {
sessionContext.set("foo", repo.loadFoo(1)); // transaction managed by spring
}
public void setFooRepo(FooRepo repo) {this.repo = repo};
}
// View
for (Something something : foo.getStuff()) {
// Ooops transaction is closed! stuff is lazily loaded so NOT AVAILABLE
// practical solutions:
// - do not load lazily (Foo.hbm.xml)
// - or force loading by getting all Somethings in the controller
}

Categories