CDI injection source not available in Jersey sub-resource - java

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.

Related

how to initialize a bean in spring container once and use it everywhere

actually i'm using spring for developing a web application, the problem i'm facing is that i'm initializing a bean as soon as the spring container is getting loaded, now i have to use that bean in different parts of my program.
constraints that i have
1. i can get application context everywhere and get that bean but according to my problem i should get that bean without writing that redundant code again and again.so is there any way by which i can initialize that bean and use it directly everywhere in my program.
If you already initialized your bean you can get access to it via #Autowired from each Component in your Spring Application.
private SomeClass myBean;
#Autowired
public void setMyBean(SomeClass myBean){
this.myBean =myBean;
}
Or just:
#Autowired
private SomeClass myBean;
I prefer the first method, looks fancier in my eyes.
You should not get your bean from the context directly, instead you should #Autowire them and let Spring inject it for you.
Here’s an example of two dependencies injected via constructor:
#Component
public class Car {
private final Engine engine;
private final Transmission transmission;
#Autowired
public Car(Engine engine, Transmission transmission) {
this.engine = engine;
this.transmission = transmission;
}
}
Note that your class must be a Spring Component itself in order for the injection to occur.
There are actually three types of dependency injection in Spring: constructor, field and setter injection. Spring team recommends using the constructor based approach, and this post brings very nice arguments to this point: https://blog.marcnuri.com/field-injection-is-not-recommended/
You can refer to this link for more information on constructor-based injection: https://www.baeldung.com/constructor-injection-in-spring

JAX-RS resource as POJO vs CDI vs EJB

A JAX-RS root resource is defined by a #Path annotation and might use managed components for doing the actual work, for example:
#Path("resource")
public class Resource
{
#Inject
Worker worker;
#GET
public String getDetails() {
return worker.getDetails();
}
}
Now I can transfer this JAX-RS root resource to either a CDI bean:
#RequestScoped
#Path("resource")
public class Resource {...}
Or to an EJB:
#Stateless
#Path("resource")
public class Resource {...}
So - what are the consequences of doing it the POJO, the CDI or the EJB way? From the outside, a request to the URL delivers three times the same thing, but what happens under the hood and how do the injected components relate to each case?
It pretty much comes down to context. Do you need the extra facilities that an EJB provides (well defined transaction semantics, proxied stateless pooled handlers, cluster support, etc.), or do you just need dependency injection?
Just using a CDI bean will give you that off the shelf, if that's all you need. If you don't even need that, a POJO will provide your simplest bang for the buck.

CDI Producermethod ignored

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.

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"

CDI Injection of an EJB leads to NullPointerException

I am new to Java EE 6 and CDI. I have read a couple of tutorials and the weld documentation. However something that should work from my understanding doesn't so I need help.
I have the following situation. I created a Java EE 6 Application with NetBeans 7.0.1 using the maven archetype supplied with the IDE and I deploy to GlassFish 3.1 also supplied by the IDE.
The beans.xml is located in the META-INF directory of my EJB jar.
I have created a class that works soley as a producer class for my EJB Artifacts (and EntityManager)
#Stateless
public class EjbArtifactProducer {
#PersistenceContext(unitName = "trackProfiler-PU")
private EntityManager em;
#EJB
private UserFacadeLocal userFacade;
#EJB
private AuthServiceLocal authService;
#EJB
private NewsEntryFacadeLocal newsEntryFacade;
#EJB
private RoleFacadeLocal roleFacade;
#EJB
private TrackCommentFacade trackCommentFacade;
#EJB
private TrackFacade trackFacade;
#EJB
private TrackTypeFacade trackTypeFacade;
#EJB
private WaypointFacadeLocal waypointFacade;
#Produces
public AuthServiceLocal getAuthService() {
return authService;
}
#Produces
public EntityManager getEm() {
return em;
}
#Produces
public NewsEntryFacadeLocal getNewsEntryFacade() {
return newsEntryFacade;
}
#Produces
public RoleFacadeLocal getRoleFacade() {
return roleFacade;
}
#Produces
public TrackCommentFacade getTrackCommentFacade() {
return trackCommentFacade;
}
#Produces
public TrackFacade getTrackFacade() {
return trackFacade;
}
#Produces
public TrackTypeFacade getTrackTypeFacade() {
return trackTypeFacade;
}
#Produces
public UserFacadeLocal getUserFacade() {
return userFacade;
}
#Produces
public WaypointFacadeLocal getWaypointFacade() {
return waypointFacade;
}
}
I tried to apply the #Produces annotation directly to the fields an on methods as shown above.
However the following does not inject anything in another EJB
#Inject
private NewsEntryFacadeLocal newsEntryFacade;
This is done in a stateless session ejb but when I try to access newsEntryFacade in any of my business methods a NullPointerException is thrown. So clearly no Injection is happening or my producers produce null references.
Am I missing something? Or should this work according to CDI/Weld?
Strangely it seems to work that way when I try to #Inject EJBs into the web application part (however i needed an extra producer class in my .war for this to work, is this as it should be?).
EDIT: The project works with an ant build (generated by NetBeans). Are there issues with the Maven archetype provided by NetBeans? It seems that with the Maven archetype there are some issues with CDI injection between the war and ejb modules. I found that if I had separate producers in the web and ejb module Glassfish generates a deployment error stating that there are two indistinguishable implementations of an interface. But when I remove the producer in the web module Weld complains that the EJB i want to inject into my beans in the web module cannot be resolved. Also with the Ant build EJBs can be #Injected without a producer while the maven build needs producer fields on a class. I can't explain how this could happen. After all the final deployment should be more or less equal, shouldn't it?
If you want to use #Inject then annotate it as #Named #ApplicationScoped, otherwise use #EJB when injecting your singleton.
Jordan Denison is correct. You're trying to #Inject and EJB, but you be using #EJB for EJBs. You're EJB class is probably annotated with #Stateless or something. #Inject should be used on session beans that annotated with #Named and some sort of scope.
Hard to tell whats going wrong but what definitely did not work for us is to use CDI between class loader boundaries. For example if your application is packaged as an ear file you would have your ejbs in an jar file and your webapp in your war file. In this case you can not use CDI to inject your ejbs in your web layer. The problem is that the jar and the war is loaded by different class loaders. Maybe newer CDI implementations behave different but at least JBoss 6 and Glassfish had this problem.
Try to put #Named into EjbArtifactProducer. Also, if the produces is this kind of simple, I think it's better to remove it too (else, you should do one more change).
you are mixing two different concepts... use CDI as backing beans for JSF. (CDI in Web Container) and use EJB and JPA in the Business Layer... the CDI layer can inject a EJB to call the specific business method.
in this case you have a clean separation on concerns.
BTW: you do not need any EJB interfaces at all! use only interfaces if you have a requirements to communicate from remote... (#Remote). with the #LocalBean annotation you can inject directly the EJB itself..
if you have e clean separation of layers each with his own concern i think you better find the reason for this NullPointerException.. and i think your NullPointerException does not exists any more after this...
Layering:
Web Browser --> JSF Facelet --> CDI Backing Bean --> EJB Service(s) --> EntityManager

Categories

Resources