Java EE, CDI - #inject not working; null - java

I am somewhat new to Java EE (dependency injection) and I can't figure out why #Inject is giving me null, yet InitialContext.doLookup does work.
Here is my bean. It is just a DAO. A wrapper for EntityManager basically
#Stateless
public class PersonManager {
#PersistenceContext("unitName="PersonData")
EntityManager em;
...
}
Here is a REST service, where I am trying to utilize PersonManager:
#Path("/PersonService")
#RequestScoped
public class PersonService {
#Inject private PersonManager manager; //this comes up null
#GET
#Produces("text/html")
public String getAllPersons() {
List<Person> personList manager.findAll(); //null pointer exception, manager null
}
}
Now what is weird is, if I do a lookup on PersonManager, it does work, like this:
#GET
#Produces("text/html")
public String getAllPersons() {
try {
manager = InitialContext.doLookup("java:global/PersonApp/PersonData/PersonManager");
}
catch(Exception e) {
e.printStackTrace();
}
List<Person> personList manager.findAll(); //this works!
}
Any idea why #Inject doesn't work here? I am using an EAR with a WAR and JAR within it like this:
EAR (PersonApp)
--JAR (PersonData - ejb module - contains PersonManager)
--WAR (PersonRest - web module - contains PersonService)

The problem turned out to be adding PersonService as a singleton in the rest application registration.
#ApplicationPath("api")
public class RestApplication extends Application{
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> empty = new HashSet<Class<?>>();
public RestApplication(){
//below line caused #Inject not to work. commented out
//singletons.add(new PersonService());
}
#Override
public Set<Class<?>> getClasses() {
return empty;
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}

Related

JPA EntityManager not working when using Guice's PrivateModule

I have a service with a persistence setup using JPA, Hibernate and Guice (if it's useful, I'm not using Spring). This is the first, working version of my code:
public class BookDao {
#Inject
protected Provider<EntityManager> entityManagerProvider;
protected EntityManager getEntityManager() {
return entityManagerProvider.get();
}
#Transactional
public void persist(Book book) {
getEntityManager().persist(book);
}
}
public class MyAppModule extends AbstractModule {
#Override
protected void configure() {
initializePersistence();
}
private void initializePersistence() {
final JpaPersistModule jpaPersistModule = new JpaPersistModule("prod");
jpaPersistModule.properties(new Properties());
install(jpaPersistModule);
}
}
But now I need to configure multiple persistence units. I'm following the advice in this mailing list, and according to them, I should move my module logic to a private module. I did as suggested and created a second version of the same code, the changes are commented below:
#BindingAnnotation
#Retention(RetentionPolicy.RUNTIME)
#Target({ FIELD, PARAMETER, METHOD })
public #interface ProductionDataSource {} // defined this new annotation
public class BookDao {
#Inject
#ProductionDataSource // added the annotation here
protected Provider<EntityManager> entityManagerProvider;
protected EntityManager getEntityManager() {
return entityManagerProvider.get();
}
#Transactional
public void persist(Book book) throws Exception {
getEntityManager().persist(book);
}
}
public class MyAppModule extends PrivateModule { // module is now private
#Override
protected void configure() {
initializePersistence();
// expose the annotated entity manager
Provider<EntityManager> entityManagerProvider = binder().getProvider(EntityManager.class);
bind(EntityManager.class).annotatedWith(ProductionDataSource.class).toProvider(entityManagerProvider);
expose(EntityManager.class).annotatedWith(ProductionDataSource.class);
}
private void initializePersistence() {
JpaPersistModule jpaPersistModule = new JpaPersistModule("prod");
jpaPersistModule.properties(new Properties());
install(jpaPersistModule);
}
}
The newly annotated EntityManager is being correctly injected by Guice and is non-null, but here's the fun part: some of my unit tests started failing, for example:
class BookDaoTest {
private Injector injector;
private BookDao testee;
#BeforeEach
public void setup() {
injector = Guice.createInjector(new MyAppModule());
injector.injectMembers(this);
testee = injector.getInstance(BookDao.class);
}
#Test
public void testPersistBook() throws Exception {
// given
Book newBook = new Book();
assertNull(newBook.getId());
// when
newBook = testee.persist(newBook);
// then
assertNotNull(newBook.getId()); // works in the first version, fails in the second
}
}
In the first version of my code the last line above just works: the entity is persisted and has a new id. However, in the second version of my code (using a PrivateModule and exposing an annotated EntityManager from it) the persist() operation doesn't work anymore, the entity is without an id. What could be the problem? I didn't do any other configuration changes in my environment, and I don't see error messages in the logs. Let me know if you need more details.
It turns out that the problem was the #Transactional annotation. In the first version of my code, Guice automatically adds interceptors for managing the transaction. By doing a debug, I found out that before executing my persist(Book book) method, Guice calls the following method from the com.google.inject.internal.InterceptorStackCallback package:
public Object intercept(Object proxy, Method method, Object[] arguments, MethodProxy methodProxy)
In the second version of my code, when I exposed the persistence unit from a private module the above interceptor was no longer called, leaving my persist operation without transaction handling. This is a known issue and is by design.
As a workaround I had to implement transactions by hand, making my code more verbose. I also had to change the way the entity manager is injected. This solution worked for me:
public class BookDao {
#Inject
#Named(PROD_PERSISTENCE_UNIT_NAME)
private EntityManagerFactory entityManagerFactory;
private EntityManager getEntityManager() {
return entityManagerFactory.createEntityManager();
}
public void persist(Book book) throws Exception {
EntityManager em = getEntityManager();
try {
em.getTransaction().begin();
em.persist(book);
em.getTransaction().commit();
} catch (Exception e) {
em.getTransaction().rollback();
throw e;
} finally {
em.close();
}
}
}
public class MyAppModule extends PrivateModule {
public static final String PROD_PERSISTENCE_UNIT_NAME = "prod";
#Override
protected void configure() {
initializePersistence();
}
private void initializePersistence() {
// persistence unit set to prod DB
final JpaPersistModule jpaPersistModule = new JpaPersistModule(PROD_PERSISTENCE_UNIT_NAME);
// connection properties set to suitable prod values
jpaPersistModule.properties(new Properties());
install(jpaPersistModule);
// expose bindings to entity manager annotated as "prod"
bind(JPAInitializer.class).asEagerSingleton();
bind(PersistService.class).annotatedWith(named(PROD_PERSISTENCE_UNIT_NAME)).to(PersistService.class).asEagerSingleton();
expose(PersistService.class).annotatedWith(named(PROD_PERSISTENCE_UNIT_NAME));
bind(EntityManagerFactory.class).annotatedWith(named(PROD_PERSISTENCE_UNIT_NAME)).toProvider(binder().getProvider(EntityManagerFactory.class));
expose(EntityManagerFactory.class).annotatedWith(named(PROD_PERSISTENCE_UNIT_NAME));
bind(EntityManager.class).annotatedWith(named(PROD_PERSISTENCE_UNIT_NAME)).toProvider(binder().getProvider(EntityManager.class));
expose(EntityManager.class).annotatedWith(named(PROD_PERSISTENCE_UNIT_NAME));
bind(UnitOfWork.class).annotatedWith(named(PROD_PERSISTENCE_UNIT_NAME)).toProvider(binder().getProvider(UnitOfWork.class));
expose(UnitOfWork.class).annotatedWith(named(PROD_PERSISTENCE_UNIT_NAME));
}
}
As a lesson, be very watchful around annotations and other such "magic" that modifies your code under the hood, finding bugs becomes quite difficult.

Spring Entities Not Saved To Database

We have set up the Spring Framework like this:
#Eager
public interface CatalogElementRepository extends PagingAndSortingRepository<CatalogElementEntity, Long> {
}
#Service
public class CatalogImpl implements CatalogManager {
#Inject
CatalogElementRepository catalogElementRepository;
#Override
public CatalogElement createCatalogElement(CatalogElementEntity catalogElement) {
return this.catalogElementRepository.save(catalogElement);
}
}
#Stateless
#Remote(CatalogManager.class)
public class CatalogManagerBean implements CatalogManager {
#Inject
CatalogManager delegate;
#Override
public CatalogElement createCatalogElement(CatalogElementEntity catalogElement) {
return this.delegate.createCatalogElement(catalogElement);
}
}
So whenever someone calls the method on the remote interface createCatalogElement, I'd assume the entity gets stored in the database. It does not (weirdly enough, findOne still returns the very same entity, but it can't be found via findByProperty).
Other questions said to add #Transactional, so I added #javax.transaction.Transactional and org.springframework.transaction.annotation.Transactional on the methods and classes to be on the safe side, nothing worked.
What could be the problem?
I don't see any configuration files for the Spring Framework, but it's a legacy project, so they might just be hidden very well.
For some reason using this class as a producer for the EntityManager helped:
public class SpringConfig {
#PersistenceUnit
EntityManagerFactory emf;
#PersistenceContext
EntityManager em;
#Produces
#ApplicationScoped
public EntityManagerFactory createEntityManagerFactory() {
return this.emf;
}
#Produces
public EntityManager createEntityManager() {
return this.em;
}
public void close(#Disposes EntityManagerFactory entityManagerFactory) {
entityManagerFactory.close();
}
public void close(#Disposes EntityManager entityManager) {
entityManager.close();
}
}

How do I utilize supportsNullCreation() in Jersey?

I have an injectable provider that may or may return null. I am getting an exception when it is null. I registered the provider as a Singleton, can I possibly register it as a type of SingletonContext that I customize to return true for supportsNullCreation()? I think if I can do that then even if findOrCreate() returns null, my code will still run which is what I want.
#ApplicationPath("rest")
public class MyApplication extends ResourceConfig
{
public MyApplication()
{
...
// Provider of DB
this.register( new AbstractBinder()
{
#Override
public void configure()
{
bindFactory(DbManager.class).to(EntityManagerFactory.class).in(Singleton.class);
}
});
}
Then it is used like this:
#Singleton
#Path("myservice")
public class WebServiceClass
{
// NOTE: Right now I have to comment this to run without a DB
#Inject
private EntityManagerFactory entityManagerFactory = null;
...
The exception I get is this...
java.lang.IllegalStateException: Context
org.jvnet.hk2.internal.SingletonContext#6cae5847 findOrCreate returned a null for
descriptor SystemDescriptor(
implementation=com.db.DbManager
contracts={javax.persistence.EntityManagerFactory}
scope=javax.inject.Singleton
qualifiers={}
descriptorType=PROVIDE_METHOD
descriptorVisibility=NORMAL
metadata=
rank=0
loader=org.glassfish.hk2.utilities.binding.AbstractBinder$2#7050f2b1
proxiable=null
proxyForSameScope=null
analysisName=null
id=145
locatorId=0
identityHashCode=863132354
reified=true)
at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2075)
...
I would recommend changing the design a bit. Using the EntityManagerFactory in the resource class is not very great design. You are left with code like
public class Resource {
private EntityManagerFctory emf;
#POST
public Response get(Entity e) {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(e);
em.getTransaction().commit();
em.close();
}
}
There are a lot of things wrong with this picture. For one you are breaking the [Single Responsibility Principle][1]. Secondly this doesn't allow you to elegantly handle the null EMF, even if it was possible. You have this all over the place
if (emf != null) {
// do code above
} else {
// do something else.
}
Also it is no great for testing. The common pattern is to use a DAO layer. Personally I even add a service layer in between the DAO and the REST layer, but you can get away with just a DAO layer.
For example what I would do is create a common abstraction interface for the data access calls.
public interface DataService {
Data getData();
}
Then create an implementation for db access
public class WithDbService implements DataService {
private EntityManagerFactory emf;
public WithDbService(EntityManagerFactory emf) {
this.emf = emf;
}
#Override
public Data getData() {
...
}
}
Then create another implementation without db access.
public class WithoutDbService implements DataService {
#Override
public Data getData() {}
}
Then you can use a Factory to create the DataService. What you will do is use the ServiceLocator to try and find the EMF. If it is not null, return the WithDbService else return the WithoutDbService
public class DataServiceFatory implements Factory<DataService> {
private DataService dataService;
#Inject
public DataServiceFactory(ServiceLocator locator) {
// abbreviated for brevity
EMF emf = locator.getService(EMF.class);
if (emf != null) {
dataService = new WithDbService(emf);
} else {
dataService = new WithoutDbService();
}
}
#Override
public DataService provider() { return dataService; }
}
[...]
bindFactory(DataServiceFactory.class).to(DataService.class).in(..);
Then you can just inject DataService every where. As long as the two implementations follow the contract, it should work just fine.
There may be some design improvements, but it is a big step up from using the EMF directly in the resource class.

Unable to Inject CDI Bean with rest Easy

I am not able to inject the cdi bean in Resteasy. While debugging it always seems to show null pointer exception. ie 'jaxRsImpl' in the below code is always null. I am trying to run on jboss eap 6.2
#Path("/jaxrs-service")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class JAXRSService {
#Inject
private JAXRSImpl jaxRsImpl;
#POST
#Path("/authenticate")
#Consumes(MediaType.APPLICATION_JSON)
public Response authenticate(Credentials user) {
return jaxRsImpl.authenticate(user);
}
}
And the class which i intend to inject is
#RequestScoped
public class JAXRSImpl {
public Response authenticate(Credentials user) {
// Some logic
}
}
As my application is web so i have added beans.xml inside WEB-INF folder
My Initialiser looks like
#ApplicationPath("/rest")
public class JAXRSInitializer extends Application {
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> classes = new HashSet<Class<?>>();
public JAXRSInitializer() {
singletons.add(new JAXRSService());
classes.add(JAXRSImpl.class);
}
#Override
public Set<Class<?>> getClasses() {
return classes;
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}
You need to ensure that your application is CDI aware. Here are some of the key requirements:
In JAX-RS, don't list out your classes/singletons. Allow the container to discover them. Basically create an empty Application implementation.
Make sure you have a valid beans.xml
Make sure your rest endpoints have a valid scope - e.g. #RequestScoped
The first bullet is key, since you're manually instantiating your service, rather than allowing the container to find them.

Call spring inject class from a static method from another class

Well, i have a class with #Component anotation, this class makes some selects in database, see:
#Component(value = "parametroRelatorioHelper")
public class ParametroRelatorioHelper {
#Autowired
private BasicDAO dao;
public ParametroRelatorio getParametroByNome(String nome) {
List<ParametroRelatorio> parametros = (List<ParametroRelatorio>) dao
.findByNamedQuery(ParametroRelatorio.FIND_BY_NOME,
new NamedParams("nome", nome));
if (parametros.size() > 0)
return parametros.get(0);
else
return null;
}
public List<ParametroRelatorio> getAll() {
return (List<ParametroRelatorio>) dao
.findByNamedQuery(ParametroRelatorio.FIND_ALL);
}
public BasicDAO getDao() {
return dao;
}
public void setDao(BasicDAO dao) {
this.dao = dao;
}
}
Now, i have a "Helper" class, where user can call your method directly (static method) but i need call a method from ParametroRelatorioHelper, see:
public class ReportHelper {
public static void call(){
//how can i do it without #Component injection
parametroRelatorioHelper.getAll();
}
}
It sounds like your architecture is incorrect, instead the ReportHelper should be a component too and the dependencies should be injected in it, otherwise it collides with the idea of the Spring IOC, helper methods should not rely on components on services...

Categories

Resources