I'm working in a project with Java EE 7 and I need to inject a javax.ejb.#Stateless bean into another. Both beans have a similar structure:
#Stateless
public class OperationRepository extends GenericRepository<Operation> {
#PersistenceContext
private EntityManager entityManager;
public OperationRepository() {
}
/*Implementation of abstract methods, getters/setters, etc*/
}
#Stateless
public class MenuRepository extends GenericRepository<Menu> {
#PersistenceContext
private EntityManager entityManager;
#Inject
private OperationRepository operationRepository;
public MenuRepository() {
}
/*idem OperationRepository*/
public List<Menu> getMenuFromOperation(...) {
// Do something where I need operationRepository
}
}
The GenericRepository<E> is just an abstract class with some common methods and other abstract methods, doesn't matter here.
The problem is that in the getMenuFromOperation() method I get a NullPointerException. Debugging the code I realized that the injected operationRepository is null when requested in the method.
Why does fail the injection point? what am I missing here?
Just to make a little test, I injected manually by instantiating a default OperationRepository in the MenuRepository constructor, but in that case the OperationRepository.entityManager isn't injected (is null)
Thanks in advance for your answers.
Edit #1
As requested by John Ament, here it goes:
All my code is in a single jar file. It's a Maven module that will be deployed together with a web module (a war package) in a Glassfish Server 4.1.
The beans.xml still doesn't exists yet, because the project isn't ready to be deployed (I didn't perform any integration test yet)
The MenuRepository is leveraged from a #Test class because I'm still developing MenuRepository.
The code for the test class is as follows:
public class MenuOperationRepositoryUTest extends BaseTestRepository {
private MenuRepository menuRepository;
private OperationRepository operationRepository;
#Before
public void initTestCase() {
initTestDB();
menuRepository = new MenuRepository();
menuRepository.setEntityManager(em);
operationRepository = new OperationRepository();
operationRepository.setEntityManager(em);
}
#After
public void finalizeTestCase() {
closeEntityManager();
}
/*Some successful tests*/
#Test
public void showMenuFromOperation() {
// Insert some dummy data into the test DB (HSQL)
// This method needs the injected OperationRepository in MenuRepository
List<Menu> menu = menuRepository.getMenuFromOperation(...);
// Assertions
}
}
And the BaseTestRepository is as follows:
#Ignore
public class BaseTestRepository {
private EntityManagerFactory emf;
protected EntityManager em;
// This is a helper class that contains all the boilerplate to begin transaction
// and commit, it's used to insert data in the test DB
protected DBCommandExecutor dbCommandExecutor;
protected void initTestDB() {
// sigeaPU is the name declared in persistence.xml
emf = Persistence.createEntityManagerFactory("sigeaPU");
em = emf.createEntityManager();
dbCommandExecutor = new DBCommandExecutor(em);
}
protected void closeEntityManager() {
em.close();
emf.close();
}
}
I think that's all I got so far. Let me know any clue you can get (or guess)
Because you're testing out of the CDI container you should also set your dependencies manually in the #Before method of the test class.
menuRepository.setOperationRepository(operationRepository)
Related
after I received a very good answer in my post about Guice injection in general, I wanted to know, if you could also help me with injection of EntityManagers in Guice.
I already read the article https://github.com/google/guice/wiki/JPA about Guice JPA. My code looks like this (I need the providers for my work):
Provider:
public class DatabaseControllerProvider implements Provider<DatabaseControllerInterface> {
private final Provider<EntityManager> entityManagerProvider;
#Inject
public DatabaseControllerProvider(final Provider<EntityManager> manager) {
this.entityManagerProvider = manager;
}
#Override
public DatabaseControllerInterface get() {
return new DatabaseControllerImpl(entityManagerProvider.get());
}
}
Constructor of DatabaseControllerImplementation:
public class DatabaseControllerImpl implements DatabaseControllerInterface {
private final EntityManager em;
#Inject
public DatabaseControllerImpl(final EntityManager manager) {
this.em = manager;
}
}
Top level I call this:
public LogInFront() {
final Injector injector = Guice.createInjector(new ModuleBinder(), new JpaPersistModule("ATVPersistence"));
final PersistService persistService = persistenceInjector.getInstance(PersistService.class);
persistService.start();
logInService = injector.getInstance(LogInServiceInterface.class);
}
to instantiate the JPAPersistService with my database.
I receive an error, that no Implementation for EntityManager was bound, but if I call
...
public LogInFront() {
final Injector injector = Guice.createInjector(new JpaPersistModule("ATVPersistence"));
final PersistService persistService = persistenceInjector.getInstance(PersistService.class);
persistService.start();
logInService = injector.getInstance(LogInServiceInterface.class);
}
The instantiation works correctly, database works fine, and everything is nice and easy.
So my guess is, that there's something wrong with my GuiceModule. As seen above, when I'm not calling the new ModuleBinder(), everything works just fine.
public class ModuleBinder extends AbstractModule {
#Override
protected void configure() {
bind(DatabaseControllerInterface.class).asEagerSingleton();
bind(AnalyzerInterface.class).asEagerSingleton();
bind(SystemAdministrationInterface.class).asEagerSingleton();
bind(LogInServiceInterface.class).asEagerSingleton();
}
}
-----------------------------EDIT-------------------------------------
Rewrote above section.
Tl;dr edition:
ModuleBinder messes up Injection of EntityManager -why?
---------------------------Found error-------------------------------
I feel kind of dumb, I found the error. When taking a look into the ModuleBinder you can see, that it binds everything as EagerSingleton, but obviously, the EntityManager does not exist yet (the PersistService is started after creating the Injector). I created a new post on this here: https://stackoverflow.com/questions/47181835/jpapersistencemodule-guice-injector
May it help other people!
Best regards,
JosefRucksack
I feel kind of dumb, I found the error. When taking a look into the ModuleBinder you can see, that it binds everything as EagerSingleton, but obviously, the EntityManager does not exist yet (the PersistService is started after creating the Injector).
Calling
final Injector injector = persistenceInjector.createChildInjector(new ModuleBinder());
Fixes everything. It creates a childInjector that knows everything the parent knows, therefore the PersistenceService is already started and you can inject the EntityManager into everything.
I am learning to use JPA. And I'm a little confused.
According JPA EntityManager manages transactions. But a design pattern is to inject the EntityManager in DAOs. So how is possible that are different EntityManager to the same transaction?
This is the case I want to solve
I have the DAOs defined
#Repository
JPARepository1 {
#PersistenceContext
protected EntityManager em;
....
.
#Repository
JPARepository2 {
#PersistenceContext
protected EntityManager em;
....
I have a Service
#Service
public class ServiceImpl1 {
#Autowired
private JPARepository1 repo1;
#Autowired
private JPARepository2 repo2;
public void mainMethod(){
Object o= transactionalMethod1();
try{
transactionalMethod2(o);
}catch (Exception e){
transactionalMethod3(o);
}
}
private Object transactionalMethod1(){
....
}
private void transactionalMethod2(Object o){
....
}
private void transactionalMethod3(Object o){
....
}
Then from #Controller I will invoke mainMethod().
What would be the right way to do transactional to transactionalMethod1, transactionalMethod2 and transactionalMethod3,within the same Service and using the same Repository's.
I would like it if there is an exeption in transactionalMethod2, this abort the transaction, but keep the transactions of transactionalMethod1 and transactionalMethod3
Thanks, sorry for my English
Usually you configure one EntityManager, so the wired manager is always the same, the one you configured. The instance of this manager though, is different in every wiring.
So, every transaction in your service uses a different instance of the EntityManager and thus every transaction invoked is seperated from each other.
As so, an exception in transactionalMethod2 doesn't necessarily affects the transactionalMethod1 and transactionalMethod3
What would be the right way to do transactional to transactionalMethod1, transactionalMethod2 and transactionalMethod3,within the same Service and using the same Repository's.
Now, you have two options to do service methods transactions
1) You could annotate your whole #Service like that:
#Service
#Transactional
public class ServiceImpl1 {
....
so every method declared here is also a transaction.
2) You could annotate each method as #Transactional:
#Transactional
private Object transactionalMethod1(){
....
}
#Transactional
private void transactionalMethod2(Object o){
....
}
#Transactional
private void transactionalMethod3(Object o){
....
}
If you want to use a single repository just #Autowired a single one and use it in your #Transactional method. E.g:
#Service
#Transactional
public class ServiceImpl1 {
#Autowired
private JPARepository1 repo1;
public void mainMethod(){
Object o= transactionalMethod1();
try{
transactionalMethod2(o);
}catch (Exception e){
transactionalMethod3(o);
}
}
private Object transactionalMethod1(){
return repo1.findOne();
}
private void transactionalMethod2(Object o){
repo1.create(o);
}
private void transactionalMethod3(Object o){
repo1.delete(o)
}
I have a class called Menu, annnotated as #Entity where i need to use a method inside a class called GestoreMessaggi
....
#Component
#Entity
#Table(name="menu")
public class Menu implements Serializable{
#Autowired
#Transient // because i dont' save this field on the DB
private GestoreMessaggi gestoreMessaggi;
.....
public void setCurrentLanguage(){
/* I got the error both if use gestoreMessaggi
this way and if I use the autowired istance of GestoreMessaggi*/
GestoreMessaggi gestoreMessaggi = new GestoreMessaggi();
gestoreMessaggi.gest();
}
.....
This is the relevant code of the class GestoreMessaggi
#Component
public class GestoreMessaggi {
#Autowired
private ReloadableResourceBundleMessageSource messageSource;
public void gest(){
messageSource.doSomething() <--- here messageSource is null
}
}
When, I call gestoreMessaggi.gest(); from Menu class, I got an error because messageSource is null. The gestoreMessaggi istance is NOT null, is null just messageSource
IMPORTANT: I get null on messageSource only when I call GestoreMessaggi from classes annotated as #Entity.
In ds-servlet.xml I tell Spring to scan the pakages that contain Menu and GestoreMessaggi classes:
//Menu package
<context:component-scan base-package="com.springgestioneerrori.model"/>
//Gestore messaggi package
<context:component-scan base-package="com.springgestioneerrori.internazionalizzazione"/>
Thank you
You can follow two approaches:
Try to get an instance of a Spring-managed bean from within a method of your #Entity class
Change the design as suggested by #Stijn Geukens and make your entity a POJO without any logic or dependency injection machanisms
If you go by option 1, you have to explicitly access Spring's context and retrieve an instance of the bean you need:
#Component
public class Spring implements ApplicationContextAware {
private static final String ERR_MSG = "Spring utility class not initialized";
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static <T> T bean(Class<T> clazz) {
if (context == null) {
throw new IllegalStateException(ERR_MSG);
}
return context.getBean(clazz);
}
public static <T> T bean(String name) {
if (context == null) {
throw new IllegalStateException(ERR_MSG);
}
return (T) context.getBean(name);
}
}
You need to make Spring scan this class in order for this to work.
Then, inside your #EntityClass, do this:
public void setCurrentLanguage(){
GestoreMessaggi gestoreMessaggi = Spring.bean(GestoreMessaggi.class);
gestoreMessaggi.gest();
}
And that would be all. Note that you wouldn't need to autowire GestoreMessaggi into your #Entity any more. Please also note that this approach is not recommended neither by Spring nor by most of the community, since it couples your domain classes (your #Entity class) to Spring classes.
If you go by option 2, then all you need to do is let Spring resolve the autowiring as usual, but outside of your entity (i.e. in a dao or service), and if your entity needs you to fill it with some message or whatever, just invoke a setter on it. (Then it's up to you to make your #Entitys attribute #Transient or not, depending on your requirements).
Spring context does not manage entities (in general does not manage objects instantiated using new), this is why you cannot autowire beans (that come from Spring's context) in entities.
Best practices suggest to keep only getter and setter in your entities, leaving the business logic to the service layer.
A common approach is Service <-> DAO <-> Entity. Example:
Service layer:
#Service
public interface GestoreMessaggi {
public void gest();
}
public class GestoreMessaggiImpl implements GestoreMessaggi {
#Autowired
private MenuDao menuDao;
#Override
public void gest() {
// 1) retrieve your entity instance with menuDao
// 2) do stuffs with your entity
// 3) maybe save your entity using menuDao
}
}
DAO layer:
If you use Spring Data Jpa:
public interface MenuDao extends JpaRepository<Menu, [menu-id-type]> {}
Else:
public interface MenuDao {
public Menu findOne([menu-id-type] id);
public Menu save(Menu menu);
// other methods for accessing your data
}
#Repository
public class MenuDaoImpl {
// inject EntityManager or Hibernate SessionFactory
// implement your DAO interface accessing your entities
}
Finally remember to configure Spring's beans including your #Services and your #Repositorys in your configuration (explicitly or by package scanning).
Using Spring MVC, you should inject (autowire) your #Services in a #Controller class, so the controller can call services methods, which call DAOs methods, which access your data.
I've just started using Guice and having trouble with understanding the guice way of injection. I'm very familiar with Spring, but this seems a bit different.
I have a DAO class:
public class SomeDAO {
#NotNull
private DB db = null;
public SomeDAO (String databaseName) throws Exception{
xxxxxxxxxxxxxxxxxxxxxxxx
}
}
I have a controller, say:
public class SomeController {
private SomeDAO someDAO;
}
How should i use guice here to inject someDAO object? Note that the databaseName in SomeDAO constructor should be provided from SomeController.
Thanks.
Ideally SomeController shouldn't have to know the name of the database. This would come from a configuration file or from your application context and you'd inject your DAO like this:
public class SomeController {
private final SomeDAO someDAO;
#Inject
SomeController(SomeDAO someDAO) {
this.someDAO = someDAO;
}
}
And then to inject the database name you could do something like this:
public class SomeDAO {
#NotNull
private DB db = null;
#Inject
public SomeDAO (#IndicatesDatabaseName String databaseName) throws Exception {
...
}
}
In this case Guice will provide databaseName (see https://code.google.com/p/google-guice/wiki/BindingAnnotations). If you want to give the controller knowledge of the database name then you could consider just newing the DAO from the controller (but still injecting the controller) or using assisted inject.
EDIT:
If the controller really needs to know about the database you could use assisted inject:
public class SomeController {
private final SomeDAO someDAO;
#Inject
SomeController(#Assisted String databaseName) {
this.someDAO = new SomeDAO(databaseName);
}
}
public interface ControllerFactory {
public SomeController create(String databaseName);
}
public static class MyModule extends AbstractModule {
#Override
protected void configure() {
install(new FactoryModuleBuilder()
.implement(SomeController.class, SomeController.class)
.build(ControllerFactory.class));
}
}
And then inject ControllerFactory where SomeController is needed. You could apply the same assisted injection to SomeDAO if it ends up needing more injected dependencies, as well.
I am having a bean within which I create a new Thread with Runnable:
#Component
public class MyBean {
private final Task task = new Task();
#PersistenceContext
EntityManager em;
#PostConstruct
public void init() {
task.setEntityManager(em);
new Thread(task).start();
}
public static class Task implements Runnable {
#Setter
private EntityManager em;
#Override
public void run() {
while (true) {
// working with EntityManager
Thing t = em.findById(...); // Fetching a Thing from repo
t.getSomethingList(); // LazyInit exception
wait();
}
}
}
}
Withing the init method, new Thread is created with instance of EntityManager. When I try to load something from the repository the session is instantly closed and getting any lazy field results in failed to lazily initialize a collection of role: Something, no session or session was closed exception from Hibernate.
I tried all the #Transactional annotations with no effect. I need to achieve something like OpenEntityManagerInView, but with the difference that this is not within view.
Thanks
EDIT1:
According to comments - I tried using em.getTransaction().begin(); but this is getting me Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT.
skirsch suggested that I should invoke Transactional method on some other bean. That is what I actually do - exactly as you suggested. I wanted to make things simpler and I did not realize the difference, so I demostrated the problem directly in the class Task. So to summarize, I have it exactly like skirsch suggested, but the problem persists.
As Spring is not managing your Runnable, annotating it won't have the desired effect. So you either need to use an annotated (and Spring-managed) bean from within your Runnable or you need to take care of the txn management manually.
Use Spring transaction management
You define some kind of service
#Service
public class MyService {
#PersistenceContext
EntityManager em;
#Transactional
public void doSomething() {
Thing t = em.findById(...);
t.getSomethingList();
}
}
And then your bean would look like this:
#Component
public class MyBean {
private final Task task = new Task();
#Autowired
MyService service;
#PostConstruct
public void init() {
task.setService(service);
new Thread(task).start();
}
public static class Task implements Runnable {
#Setter
private MyService service;
#Override
public void run() {
while (true) {
service.doSomething();
wait();
}
}
}
}
Manual transaction management
In case you set up JPA Resource Local Transactions, here you go:
// working with EntityManager
em.getTransaction().begin()
try {
Thing t = em.findById(...);
t.getSomethingList();
} finally {
em.getTransaction().rollback()
}
wait();