CDI Producermethod ignored - java

I am totally at a loss! I have this Class:
package com.company.resources
import com.company.transport.Repository; //an interface for an EJB
import com.company.transport.Expression; //a simple DTO, returned by the Interface
public class ResourceProducer
{
//#EJB(lookup="foo") Repository repo;
#Produces #Named("archive")
public String getArchiveString() {
return "archive";
}
#Produces #Named("repository")
public Repository getRemoteRepository(){
//return repo;
return new Repository(){
#Override
public Expression getExpression(String s, Long aLong) {
return null;
}
};
}
}
And, simply put the String one works, the other one is ignored by the container (Wildfly 9 / Weld).
At the begining I wanted to inject an EJB and getRemoteRepository was not annotated as #Named, as i only know supply one Producer for the interface Repository. Getting the errors, i changed them to be the same, to limit the scope for the error, even in the Injection Points:
package com.company.resources
public Class ExpressionProxy {
#Inject #Named("archive") String target;
#Inject #Named("repository") Repositroy repo;
}
I get:
org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type Repository with qualifiers #Default
at injection point [BackedAnnotatedField] #Inject com.company.resources.ExpressionProxy
I do not get this Exception for The String!
Also, if i annotate ResourceProducer with #ApplicationScoped - making it a Bean - I expect getting ambigous bindings - as my Producer now is found via the #Produces Annotation itself and is present in a Managed Bean.
I also only get ambigous binding Exceptions for the String, never for Repository
I moved both classes to one .war and to the same package - it simply wont work with Repository.
I did CDI injection via Interfaces before - what is the Problem here?
EDIT: to give full disclosure:
I deploy this in an ear, as a library:
app.ear/
-jaxrs.war # contains rest interface, irrelevant for this bug
-lib/
-beans.jar #contains the Producer and ExpressionProxy
-RepositoryInterface.jar # containts Repository and Expression
i tried every permutation of the 3 archives involved.
the mentioned
beans and interfaces as library in the .war
beans as additional deployment
beans as additional deployment AND in ear/lib
The beans in /lib obviously get scanned by weld, as the String does not make any problems.

Cited from the Weld documentation 2.2.3
A producer method must be a non-abstract method of a managed bean class or session bean class. A producer method may be either static or non-static. If the bean is a session bean, the producer method must be either a business method of the EJB or a static method of the bean class.
So you could annotate your ResourceProducer with #ApplicationScoped.
Note: Using any modern IDE should tell you, that you are missing the required dependencies on compile. This saves you the time to deploy your application.

Related

Dependency injection through constructor does not work for EJB bean

My app is being deployed on to IBM WebSphere. I have a simple service and I'd like to know how dependency injection works in this case.
// stateless EJB
#Stateless
public class UserService {
private UserDAO userDAO;
// btw, UserDAO is stateless EJB as well
#Inject
public UserService(UserDAO userDAO) {
this.userDAO = userDAO;
}
// biz methods ...
}
It fails with the following error:
[ERROR ] CWWKZ0002E: An exception occurred while starting the
application my-app. The exception message was:
com.ibm.ws.container.service.state.StateChangeException:
com.ibm.ws.cdi.CDIException:
com.ibm.wsspi.injectionengine.InjectionException:
com.ibm.ejs.container.EJBConfigurationException: EJB class
com.demo.app.UserService must have a
public constructor that takes no parameters
I remember there was something in EJB spec that says: the class must have a public constructor that takes no parameters and it makes sense for me that the bean instance is first instantiated by the container and afterward dependency injection is done.
On the other hand, I've found this in WELD docs:
First, the container calls the bean constructor (the default
constructor or the one annotated #Inject), to obtain an instance of
the bean.
And I am confused a little bit, why my EJB cannot be instantiated.
How is the EJB instance being created and dependencies injected when we have constructor injection point?
Any ideas? :)
So what happens is that you do not meet the requirements for initializing EJB beans.
CDI spec has some limitations on constructors - either no-args or one with #Inject.
But there is also this chapter, which specifies that in EE, the set of rules is extended by what EJB session beans require.
And now we are getting into EJB spec which requires a no-arg constructor on a bean.
This should be in chapter Enterprise Bean Class where it states
The class must define a public constructor that takes no arguments.
Now, finally moving on to whether this should work - e.g. can you have an EJB bean using CDI constructor injection?
Well, let's have a look at CDI TCK, a set of tests that all implementation and containers have to pass in order to be able to claim they implement CDI.
There, we can see this bean and this test using it - so yea, this can work, but you need to have both constructors.
EJBs are registered as CDI beans. But first they have to meet the requirements of the EJB spec.
I guess it works just by providing the no-args constructor.
the creation of EJB session beans is done by EJB container but it can choose to use CDI to provide EE resource injection but EJB resolution is delegated to the container
https://docs.jboss.org/weld/reference/2.1.0.Final/en-US/html/ri-spi.html says:
Alternatively, the integrator may choose to use CDI to provide EE
resource injection. In this case, the EE_INJECT environment should be
used, and the integrator should implement the Section A.1.4, “EJB
services”, Section A.1.7, “Resource Services” and Section A.1.5, “JPA
services”.
....
Weld registers resource injection points with
EjbInjectionServices, JpaInjectionServices, ResourceInjectionServices
and JaxwsInjectionServices implementations upfront (at bootstrap).
This allows validation of resource injection points to be performed at
boot time rather than runtime
if you interested in how CDI and EJB are integrated. you can have a look at the code of weld-EJB module and weld-integration(glassfish code)

CDI injection source not available in Jersey sub-resource

I'm using CDI in a Jersey app. On root resources, CDI injection works as expected, but whenever I return a sub-resource, the CDI injection sources are not available.
My root resource with sub-resource locator:
#Path("")
public class MyResource {
#Inject #Named("name") // works
private String name;
#Context
private ResourceContext context;
#Path("test2")
public Object test2() {
return MySubResource.class;
//return context.getResource(MySubResource.class); // this does not work either
}
}
The sub-resource:
public class MySubResource {
#Inject #Named("name") // error
private String name;
#GET
public Response test() {
return Response.ok("Name in sub resource: " + name).build();
}
}
Error:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=String,parent=MySubResource,qualifiers={#javax.inject.Named(value=name)},position=-1,optional=false,self=false,unqualified=null,1235803160)
I'm using org.glassfish.jersey.ext.cdi:jersey-cdi1x and Weld dependencies, running on Undertow, with the Weld servlet listener added to the deployment.
Again, the same injection on the root resource does work. The #Named("name") String is produced by an #ApplicationScoped producer.
Is this not supposed to work? What am I missing?
Minimal example Maven project available here:
https://gitlab.com/Victor8321/jersey-sub-resource-cdi
Note: An open issue for this exists, but not sure what the official stance on this is: https://java.net/jira/browse/JERSEY-3184
As pointed out in https://github.com/eclipse-ee4j/jersey/issues/3456, adding a dummy #Path("xyz") to the sub-resource class is a "fix". However, that exposes your sub-resource under the dummy path.
Injecting an instance just through CDI works as well (#Inject Instance<MySubResource> ..), but then Jersey-managed resources aren't available for injection, such as #Context HttpServletRequest.
I've found 2 other approaches that fully work (both CDI injection and JAX-RS injection) and have no side effects (as with #Path):
Annotate the sub resource class with #Provider.
register() the sub resource class in the ResourceConfig (or Application).
Both approaches seem to work because they make Jersey - and in turn, CDI - aware of the class.
Note: I've updated my example project accordingly for future reference.

Can #Inject be used in a pojo

I am trying to use and understand CDI, when I use #Inject in a simple pojo class, it throws me NPE.
example
Greeting.java
public Class Greeting {
public String greet() {
System.out.println("Hello");
}
}
Test.java
import javax.inject.Inject;
public class Test {
#Inject
private Greeting greeting;
public void testGreet() {
greeting.testGreet();
}
}
When I call testGreet() it throws NPE, why is the greeting instance null. Does #Inject way of adding dependency only be used in container managed bean?
Note: jar is not the problem here.
TL;DR:
#Inject-annotated fields are only populated for container-instantiated beans.
Long version:
The CDI container provides you a lot of utilities for easily injecting dependencies to your beans, but it doesn't work by magic. The container can only populate the annotated fields of a client bean if the client bean itself was instantiated by the container. When the container is instantiating the object the sequence of events is as follows:
Your bean's constructor is called.
#Inject-annotated fields (and some other
annotations, #PersistenceContext and #EJB for instance) are
populated.
#PostConstruct-annotated no-args method is called.
Your bean is finished.
You're facing a classic bootstrapping problem, how to move from non-container-managed code into container-managed code. Your options are:
Get access to an instance of BeanManager from your JavaEE container via JNDI lookup. This is technical and a bit clumsy.
Use a CDI extension library such as Apache DeltaSpike. (Example: BeanProvider.getContextualReference(Test.class, false);)
Modify your application to start in a situation where you can inject your Test class rather than calling new Test();. This can be done for example by setting up a startup singleton ejb, which calls your test in it's #PostConstruct-annotated initialisation.
Hope this helps.
You need a JavaEE container, and than you need to define Greeting and Test as managed beans. After that you can inject one in another.
Try to take a look at:
https://docs.oracle.com/javaee/6/tutorial/doc/girch.html
Your class should be implemented from Serializable for being injectable as a "CDI Bean"

Using a CDI producer causes ambiguous dependencies exception

I have a requirement to Inject the same instance of an ApplicationScoped bean into several places of my application and have created the following factory class which uses the #PostConstruct annotation to initialize the bean and the #Produces annotation to return the same instance of the bean.
#ApplicationScoped
public class CommandBusFactory implements Serializable {
private static final long serialVersionUID = 1L;
private CommandBus commandBus;
#PostConstruct
public void init() {
commandBus = new BasicCommandBus();
// Do some stuff to configure the command bus
}
#Produces
public CommandBus produceCommandBus() {
return commandBus;
}
}
The problem I've got is when I deploy the application GlassFish returns the following error message:
Exception while loading the app : CDI deployment failure:WELD-001409 Ambiguous dependencies for type [CommandBus] with qualifiers [#Default] at injection point [[BackedAnnotatedField] #Inject private myapp.web.ToDoItemCommandController.commandBus]. Possible dependencies [[Producer Method [CommandBus] with qualifiers [#Any #Default] declared as [[BackedAnnotatedMethod] #Produces public myapp.core.cdi.CommandBusFactory.produceCommandBus()], Managed Bean [class myapp.core.commandhandling.BasicCommandBus] with qualifiers [#Any #Default]]]
I can overcome this exception by adding the #Alternative annotation to the BasicCommandBus class, however this doesn't seem to be the best way of solving the problem.
I don't want to add a qualifier everywhere that I inject CommandBus into my application as using a different implementation of CommandBus would require changing the code in multiple places. The intention is that a later version of the factory will read a configuration file and depending upon a value in the configuration file it may create a different type of CommandBus.
I have read the answer to this question (https://stackoverflow.com/a/18782027/1274662) and understand why the Ambiguous dependencies exception is being thrown but what I don't know is the best way to deal with the fact that there are two possible beans that could be injected given that I want to decide which implementation is used and how it is initialised in a central location.
The questions I've got are:
Is using the #Alternative annotation on the BasicCommandBus class the right approach?
Is there a better approach that I should be using to Inject the same instance of an ApplicationScoped bean (i.e. CommandBus) into several places of my application whilst controlling which implementation created (i.e. BasicCommandBus or EnhancedCommandBus) and how it is initialised in a central location?
If you want your bean to be injectable only by the producer you can annotate BasicCommandBus and EnhancedCommandBus with #Vetoed this way you'll not have the ambiguity between the bean it self and the producer method and at every injection point it's the producer that will inject the instance.

#Inject, #EJB, #Local, #Remote, #LocalBean, etc... : confused?

I have the following configuration:
1 EAR on one GF containing 2 EJB-JARs with EJB components.
1 WAR on another Glassfish server (=> other JVM) containing web components accessing the EJB components.
I have 2 EJB business services in each EJB-JAR of my EAR, and they are all developped like this:
#Remote
public interface ServiceAItf {
...
}
#Stateless
#Local
public class ServiceAImpl implements ServiceAItf {
...
}
In my WAR, I access the EJB components via an explicit "InitialContext.lookup" on the remote interface.
In my EAR, I am quite confused about the best practice for injection, in terms of performance, architecture, and so on...
I have the following questions:
As you can see, I have declared the annotation "#Local" on the service implementation without defining the local interface. Is it correct? At least I have no error at deployment. But maybe I should use the "#LocalBean" annotation instead? I suppose that the "#LocalBean" annotation simply allows to invoke the implementation directly as a "Local" EJB, but you have to use the implementation in your code like this:
#Stateless
#Local
public class ServiceBImpl implements ServiceBItf {
#EJB
private ServiceAImpl serviceA;
...
}
What is the best way to inject one EJB into another one?
It works like this:
#Stateless
#Local
public class ServiceBImpl implements ServiceBItf {
#EJB
private ServiceAItf serviceA;
...
}
But from what I noticed, the "serviceA" injected is the remote proxy, while it is in the same JVM within the same EAR file. So I suppose that there will be an impact on the performance. That's why I have tried to inject the service like this:
#Stateless
#Local
public class ServiceBImpl implements ServiceBItf {
#Inject
private ServiceAItf serviceA;
...
}
But it doesn't work in GF, I have the following exception:
WELD-001408 Unsatisfied dependencies for type [...] ...
I then tried to create a local interface, and the injection via the annotation "#Inject" works when both services
Even if I create a local interface like this, the service is not injected via the annotation "#Inject" but is null:
#Local
public interface ServiceALocalItf {
...
}
I read a lot of articles where it is highly recommended to use "#Inject" instead of "#EJB" when it is for a local invocation. That leads me to the following question: in which case the "#Local" EJB invocation is recommended (or simply used)?
After all this analysis, I come to the following conclusion:
For each service, I create a "#Local" and a "#Remote" interface.
From WAR to EJB-JAR of EAR, make a JNDI lookup to the remote interface.
From EJB-JAR to EJB-JAR, make an injection via "#EJB" to the local interface.
For two services within the same EJB-JAR, make an injection via "#Inject" to the local interface.
What do you think about it? Is it correct?
As you can see, I have declared the annotation "#Local" on the service
implementation without defining the local interface. Is it correct?
With EJB 3.1, the requirement for local interfaces was dropped. No need to write them unless you explicitly need them.
What is the best way to inject one EJB into another one?
Couple of things to write here:
With Java EE 6, Java Enterprise has changed. A new JSR defines a so-called managed bean (don't confuse with JSF managed beans) as a sort of minimum component that can still benefit from the container in terms of dependency injection and lifecycle management. This means: If you have a component and "just" want to use DI and let the container control its lifecycle, you do not need to use EJBs for it. You'll end up using EJBs if - and only if - you explicitly need EJB functionality like transaction handling, pooling, passivation and clustering.
This makes the answer to your question come in three parts:
Use #Inject over #EJB, the concept of CDI (a) works for all managed
beans (this includes EJBs) and (b) is stateful and therefore far
superior over pure #EJB DI
Are you sure that you need EJBs for your
components?
It's definitely worthwhile to have a look at the CDI
documentation
#Inject annotation is used for java beans(POJOs) while #EJB annotation is used for enterprise java beans. When a container inject an ejb provided by #EJB annotation to another bean it also controls that ejb's lifecycle, performs pooling for stateless beans and so on(when bean which is going to be injected is not deployed the reference will be null). If you use #Inject annotation CDI mechanism simply find and create an instance of injected resource like with new operator(if the implementation of interface which is going to be injected doesn't exist the reference will be null). You can use qualifiers with #Inject annotation to choose different implementation of injected interface.

Categories

Resources