I have a Hibernate entity that I would like to put a method in. This method would call the entity manager and run a prepared statement, but I don't know how to instantiate the entity manager. Whenever I try, to autowire it like so:
#Autowired
private transient EntityManager entityManager;
the entityManager is null when I run the application. Autowiring works for all my other classes. Why can't I autowire the entityManager in my entity, and how do I execute my query in the Entity?
#Autowired is for beans, classes with #Service or #Component. Classes marked #Configuration can also use #Autowired. New instances of these classes are made and managed by Spring, if you try to create new instances of those classes #Autowired won't work there either. Such as MyClass myClass = new MyClass()
Classes marked with #Entity are not managed beans, they are made by the entity manager when you query them from the database, but when you create a new row you make a new instance. Spring doesn't do it's magic to them. You should call your stored procedure from a #Service just like you would use a #Repository or entity manager to save an #Entity.
Related
I want to inject the entityManager from Hibernate on an Hibernate Interceptor Class. I'm using EJBs and JBoss. The transaction is JTA and the provider is the org.hibernate.ejb.HibernatePersistence.
I tried to do it like that:
#Stateless(name = "HistoricInterceptor")
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class HistoricInterceptorImpl extends EmptyInterceptor implements HistoricInterceptor {
#PersistenceContext(name = "windi")
private EntityManager em;
// overriden methods, etc
}
But the reference to entityManager is always null.
Is this behaviour expected? How can I access an entityManager from within an Interceptor class?
I had given up on that exact solution. Instead, I've created another class that has the EJB Annotations. The interceptor will call that EJB by using a provider class that lookup up EJB classes on the context of the application. There, the entityManager is correctly associated.
Some days ago I heard about spring-boot.
So I started to setup my project from zero, include jpa and dont use older setups from existing projects. But now there is an understanding problem between what I've learned and what I've read about the "easy setup" with spring boot and jpa.
Usually my projects have this structur.
Model (for excample Car)
ModelDao (CarDao with the following code-example)
#Component
public class CarDao {
/** The Hibernate session factory. */
#Autowired
private SessionFactory sessionFactory;
#Transactional
public void save(Car car) {
sessionFactory.getCurrentSession().saveOrUpdate(car);
}
CarServiceImpl thats works with DAO´s (includes methods like findAll(), getCarById() or saveCar(Car car))
But now I only read about #Entity and JPA-repositorys.
Is it right to say that I dont need models and dao's because I have the #Entity-Annotation? And my ServiceImples and JPA-repositorys have the same functionality? What happend with the SessionFactory? Is all managed automatically?
You dont need DAO if you are going to use JPA-Repositories.
As well Session-Factory also not required.
Just you need one Class as model and one interface as repository and you all done.
example:
#Entity
#Table(name="COUNTRY")
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="COUNTRY_ID", nullable = false)
private Integer country_id;
#Column(name="COUNTRY_CODE")
private String country_code;
//Add getter and setter
}
interface
public interface CountryRepository extends PagingAndSortingRepository<Country, Integer> {
}
Yes you need to configure in spring.xml about where your above repository is located
<jpa:repositories base-package="com.repository" />
create transactionManager in spring.xml
and access it by using below code
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"spring.xml");
countryRepository = (CountryRepository) ctx.getBean("countryRepository");
Country country = countryRepository.findOne(1);
Is it right to say that I dont need models and dao's because I have the #Entity-Annotation?
#Entity annotation is used on models your POJOs. #Entity maps the POJO i;e class properties to the db table. How would you write your business logic if you get rid of models.
Service layer, DAO layer are all components of application design. They have their specific role. ServiceImpl proverbially manages the transactions whereas DAO/Repository layer manages the communication with the db.
Here your CarDao class should be annotated with #Repository annotation. It is a DAOImpl class.
And all your transactional methods should move to the Service layer.
And my ServiceImples and JPA-repositorys have the same functionality?
No, as I've already stated they have specific respective functionality. They are not same.
What happend with the SessionFactory? Is all managed automatically?
SessionFactory is always injected into the DAO layer. You can either manage the sessions yourself or let hibernate manage the sessions.
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
I have an app that's been working well with #Autowired #Service beans.
Now I'm adding a Validator class which is instantiated in the Controller:
BlueValidator validator = new BlueValidator(colors);
validator.validate(colorBlend, bindResult);
In the BlueValidator class I'm trying to #Autowire the blendService which is working as an #Autowired field elsewhere in the app:
public class BlueValidator implements Validator {
#Autowired
private BlendService blendService;
private Colors colors;
But for some reason after instantiating the BlueValidator, I keep getting NullPointerExceptions for the blendService.
Of course I've added the necessary context scanning:
<context:component-scan
base-package="com.myapp.controllers, com.myapp.services, com.myapp.validators" />
I also tried adding the#Autowired annotation to the constructor but that didn't help:
#Autowired
public BlueValidator(Colors colors) {
this.colors = colors;
}
Should I just pass the blendService to the BlueValidator and forget about the Autowiring or is there something obvious missing here?
If you just instantiate an object with new, Spring is not involved, so the autowiring won't kick in. Component scanning looks at classes and creates objects from them - it doesn't look at objects you create yourself.
This can be made to work, using Spring's AspectJ support, but it takes some effort.
Otherwise, you need to let Spring instantiate your objects if you wan autowiring to work.
Should I just pass the blendService to the BlueValidator and forget about the Autowiring
In your situation, I'd say yes, this is the least effort solution.
When you instantiate objects spring cannot do anything for them, so it does not get the dependencies injected (article).
In your case, you have a couple of options:
pass dependencies to the validator from the controller (where you can inject them)
make the validator a spring bean and inject it, instead of instantiating it
use #Configurable, which, via AspectJ, enables spring injection even in objects created with new
#Autowired is being used by Spring's ApplicationContext to populate those fields on creation. Since the ApplicationContext is not the one creating these beans (you are because of the keyword 'new'), they are not being autowired. You need to pass it in yourself if you are creating it.
Don't create validator manually -- allow to Spring do this work for you:
#Controller
class Controller {
#Autowired
BlueValidator validator;
void doSomething() {
...
validator.validate(colorBlend, bindResult);
...
}
}
Also pay attention that adding package com.myapp.validators to context:scan-packages not enough, you also should annotate your validator class with #Component annotation:
#Component
public class BlueValidator implements Validator {
#Autowired
private BlendService blendService;
(BTW this solution works in my project.)
I'm using IBM RAD to develop some JPA entities, and from those, corresponding JPA Manager Beans. Manager beans (which are generated by RAD) have the following member:
#PersistenceUnit
private EntityManagerFactory emf;
I'm not sure how to correclty instantiate (or get a reference to) this manager bean from a stateless EJB (3.0), so I've added a constructor to manager bean where I can pass EntityManagerFactory instance to it. I get a reference to EntityManagerFactory in an EJB by using `#PersistenceUnit' annotation like so:
#PersistenceUnit
private EntityManagerFactory _entityManagerFactory;
This seems rather unnecessary and I believe there must be a way to tell the container (Websphere 7.0 in my case) to 'bootstrap' this for me somehow, so that I get a reference to JPA manager bean right away. Is it?
Update:
It seems I haven't bean elaborate enough. Sorry for that.
There are three objects involved: JPA Entity, JPA Entity Manager and a Stateless EJB.
JPA Entity Manager class (not an EJB) is created by RAD and has convinience methods (named queries) on it. It also has defined member #PersistenceUnit private EntityManagerFactory emf. I know I can use EntityManager directly, but I'd like to use MyEntityManager for it's convinience methods.
I can get a reference to EntityManager or EntityManagerFactory in a stateless EJB by using annotations described above (and also like Bozho suggests)
I would like to get a reference to JPA Entity Manager in a stateless EJB. If I 'new' it up (new MyEntityManager()), the emf field is null. The workaround is to declare #PersistenceUnit field in an EJB and then pass it to JPA Entity Manager and use that.
Come to think of it, maybe I could declare JPA Entity Manager as an EJB and be done with it... (although this again seems unnecessary). I thought there is a method along the lines PersistenceContext.getJpaManager(MyEntityManager.class) which I am perhaps missing.
#PersistenceContext
private EntityManager em;
It seems you have your custom bean that you want to inject in other beans (it needs a local interface at least):
#EJB
private MyEntityManager em;