GlassFish 4.1.1: Unable to #Inject simple #Stateless in Java EE 7 JAX-RS App - glassfish

I am using Glassfish 4.1.1 as my Java server. I am trying to #Inject a simple #Stateless bean in my JAX-RS class having #Path annotation. Here is the exception I am getting:
javax.servlet.ServletException: A MultiException has 1 exceptions. They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=MongoCollectionStore,parent=DemoJaxrsApp,qualifiers={},position=-1,optional=false,self=false,unqualified=null,310751270)
Here is my JAX-RS config:
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#ApplicationPath("/rest")
public class JaxrsAppConfig extends Application {
}
This is how my JAX-RS resource class looks like:
#Path("/tn-collection")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class DemoJaxrsApp {
#Inject
MongoCollectionStore mongoCollectionStore;
#POST
public List<CollectionTO> getColl() {
return mongoCollectionStore.findAll();
}
}
I am using only 2 dependencies:
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.3.1</version>
</dependency>
It shouldn't be a problem with dependencies. I am not using any xml files (other than POM.xml and nb-configuration.xml, generated by Netbeans 8.1) as Java EE 7 need not have any config files. I don't know what might have going wrong.
Could anybody please help me out with this UnsatisfiedDependencyException problem?
UPDATE:
Here is my MongoCollectionStore Java class:
#Stateless
public class MongoCollectionStore {
public List<CollectionTO> findAll(MongoConfig mongoConfig) {
List<CollectionTO> tuples = new ArrayList<>();
Gson gson = new Gson();
MongoClient mongoClient = new MongoClient("127.0.0.1", 27017);
MongoDatabase mongoDB = mongoClient.getDatabase("Demo");
MongoCollection<Document> coll = mongoDB.getCollection("DemoCollection");
try(MongoCursor<Document> cursor = coll.find().iterator()) {
while (cursor.hasNext()) {
String jsonDoc = cursor.next().toJson();
CollectionTO tuple = gson.fromJson(jsonDoc, CollectionTO.class);
tuples.add(tuple);
}
}
return tuples;
}
}

I was looking through this problem on internet and found that a CDI bean can only be injected into another CDI bean. They both need to be managed by the container. So, I made my DemoJaxrsApp #RequestScoped, in order to make it a CDI bean.
For guys coming here from Google, Original (and more elaborate) answer can be found here:
Inject an EJB into JAX-RS (RESTful service)
One thing I still don't know is that when I #Injected a #Stateless resource inside my #RequestScoped class, was that resource an EJB? Or, was it a CDI bean? I guess, that's a different question altogether.

Related

CDI injection not working in REST Resource in WAS Liberty with Jersey as JAX-RS implementation

I am using websphere liberty 19.0.0.8 and I wanted to use Jersey instead of default CXF for jax-rs implementation. I removed jaxrs-2.1 feature from server xml and packaged jersey implementation jars in my webapp .war.
<featureManager>
<feature>servlet-4.0</feature>
<feature>jndi-1.0</feature>
<feature>requestTiming-1.0</feature>
<feature>monitor-1.0</feature>
<feature>localConnector-1.0</feature>
<feature>restConnector-2.0</feature>
<!-- Do not add enabled webProfile-8.0 because we want to disable default
REST implementation (Apache-CXF) provided by Liberty. We want to use Jersey
as our REST implementation because it better support multi-part streaming, -->
<!-- <feature>webProfile-8.0</feature> -->
<feature>jsp-2.3</feature>
<feature>cdi-2.0</feature>
<feature>managedBeans-1.0</feature>
<feature>jdbc-4.2</feature>
<!-- <feature>jaxrs-2.1</feature> -->
</featureManager>
Gradle build including jersey implementation
//JxRS Jersey implementation
compile group: 'org.glassfish.jersey.containers', name: 'jersey-container-servlet', version: '2.25.1'
compile group: 'org.glassfish.jersey.media', name: 'jersey-media-json-jackson', version: '2.25.1'
compile group: 'org.glassfish.jersey.media', name: 'jersey-media-multipart', version: '2.25.1'
compile group: 'com.fasterxml.jackson.jaxrs', name: 'jackson-jaxrs-json-provider', version: '2.9.0'
Extended jersey's ResourceConfig to configure my RestApplication
#ApplicationPath("/")
public class RestApplicationConfig extends ResourceConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(RestApplicationConfig.class);
public RestApplicationConfig() {
super();
configureResourcesAndFeatures();
}
private void configureResourcesAndFeatures() {
packages(RestApplicationConfig.class.getPackage().getName());
register(MultiPartFeature.class);
}
}
With all this setup my rest api works and I am able to make use of Jersey's multiple related classes in my code.
Now the problem is with CDI. In my resource class I am able to inject CDI managed resource/classes for example
#ApplicationScoped
#Path("/ping")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class PingResource {
private static final Logger LOGGER = LoggerFactory.getLogger(PingResource.class);
#Resource(lookup = "jndi_dpa_iss_rest_url")
private String issRestBaseUrlInResource;
#Inject
private DocumentService documentService;
}
In above class #Resource and #Inject are not able to resolve JNDI resource and managed bean. As soon as I enable jaxrs-2.1 feature in server.xml CDI injection works but then I loose jersey, it uses CXF.
DocumentService and its implementation class is defined as below. Everything is under same package as RestApplicationConfig class or it's sub-packages.
#ApplicationScoped
#Transactional(value = Transactional.TxType.NOT_SUPPORTED)
public class DocumentServiceImpl implements DocumentService {
// some code here
}
What do I need to use CDI in my rest resource classes?
Because there is no jersey extension for CDI 2.0 at the moment, I had to find workaround. Workaround is to manually query CDI container to the the type of bean we are interested in. This way we are manually injecting CDI bean in our resource class but the injected bean is managed bean instance so CDI has taken care of satisfying all its dependecies.
This we we are doing manual injection only in Resource layer but CDI should work fine for layer down.
Working code.
#ApplicationScoped
#Path("/ping")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class PingResource {
private DocumentService documentService = CDI.current().select(DocumentService.class).get();
}
Basically instead of #Inject manually query CDI container.

Using constructor injection with CDI in OpenLiberty

I'm building a small Java EE 8 application that should run on OpenLiberty.
It has a JAX-RS ContainerResponseFilter that looks like this:
package my.package;
import javax.inject.Inject;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
#Provider
public class MyFilter implements ContainerResponseFilter {
private final MyService myService;
#Inject
public DiagnosticsFilter(final MyService myService) {
this.myService = myService;
}
#Override
public void filter(final ContainerRequestContext request, final ContainerResponseContext response) {
// Never mind this
}
}
If I write the filter like this and start my app, the myService argument to the constructor is null.
However, if field is annoted with #Inject and the constructor is omitted, the field is being injected correctly.
The MyService class is annotated with #Stateless, and in beans.xml I have set bean-discovery-mode="all".
Any idea what I'm doing wrong? Is this actually supposed to work? The Weld documentation suggests that it should, but I'm not sure it's in the CDI spec as well...
This is a long story...And some people are working to solve the problem: JAX-RS injection != CDI injection
It shoud be solved in JAX-RS 2.2 ad CDI injection should be used in place of JAX-RS injection and JAX-RS v3.0 will totally remove the JAX-RS injection
Read this on the subject:
https://www.eclipse.org/community/eclipse_newsletter/2019/february/Jakarta_EE_9.php
https://github.com/eclipse-ee4j/jaxrs-api/issues/569
https://github.com/eclipse-ee4j/jaxrs-api/issues/639
https://groups.google.com/forum/#!topic/microprofile/gvj94XBhtvM

CDI doesn't work in a simple adapter

I've added the CDI feature to the server.xml file<feature>cdi-1.2</feature>.
My maven module contains the beans.xml inside the <module_name>/src/main/resources/META-INF folder.
This is the beans.xml content:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
</beans>
But when I use the #Inject annotation it doesn't work, my bean is always null.
Code:
package ch.webapp.presentation;
...
#Path("/test/")
public class MyController {
#Inject
private MyService myService;
#GET
#Path("/foo/{count}")
#OAuthSecurity(scope = "login")
#Produces("application/json")
public Response news(#PathParam("count") int count) {
return Response
.ok(myService.getBar(count))
.build();
}
}
EDIT:
That's my bean
package ch.webapp.service;
...
#RequestScoped
public class MyService {
public String getBar(int count) {
return "foo";
}
}
I initialize jax-rs by extended the MFPJAXRSApplication class
package ch.webapp;
...
public class AccountApplication extends MFPJAXRSApplication {
#Override
protected void init() throws Exception {
}
#Override
protected void destroy() throws Exception {
}
#Override
protected String getPackageToScan() {
return getClass().getPackage().getName();
}
}
Environment details:
Launching mfp (WebSphere Application Server 8.5.5.8/wlp-1.0.11.cl50820151201-1942) on Java HotSpot(TM) 64-Bit Server VM, version 1.8.0_172-b11 (en_CH)
Console Product version: 8.0.0.00-20180717-175523
What's wrong?
First it seems that websphere jax-rs implementation does not integrate jax-rs resources automatically unless you annotate them appropriately.
Put the jax-rs in a CDI managed context by annotating it appropriately
#Path("/test/")
#javax.enterprise.context.RequestScoped
public class MyController {
#Inject
private MyService myService;
#GET
#Path("/foo/{count}")
#OAuthSecurity(scope = "login")
#Produces("application/json")
public Response news(#PathParam("count") int count) {
return Response
.ok(myService.getBar(count))
.build();
}
}
Also be sure that the annotation used for your service is
#javax.enterprise.context.RequestScoped
Based on the inputs provided by you please go through the below checklist.
Your services and controllers are in the same module and its packaging type is war, So you must place your beans.xml in this path src/main/resources/WEB-INF/beans.xml. (If this is Java EE 7 application then beans.xml is optional.
In your AccountApplication class try hardcoding the package name to ch.webapp.presentation
#Override
protected String getPackageToScan() {
return "ch.webapp.presentation";
}
This is just to check Behaviour of MFPJAXRSApplication.getPackageToScan() method whether it is scanning the specified package only or its child packages too.
Except these, everything seems fine to me. If this still doesn't work add complete application startup logs so that community can find the root cause of it.
This is classical mistake. CDI works for managed beans (for instance EJB's and servlets). If you want to enable it on your JAXRS bean, you have to make it "managed", that is annotate MyController as (for instance) javax.annotation.ManagedBean or as a javax.ejb.Stateless.
Also beware that in case of webapp (.war), the beans.xml file has to be located in the WEB-INF folder !

Unsatisfied dependencies with Weld during integration testing

I am able to deploy a RESTEasy application working well with Weld (meaning my CDI works) but I am having some trouble with my integration tests. I get this error:
org.jboss.weld.exceptions.DeploymentException:
WELD-001408: Unsatisfied dependencies for type SomeService with qualifiers #Default
while testing:
#RunWith(WeldJUnit4Runner.class)
public class SomeServiceIT {
#Inject
private SomeService service;
#Test
public void test() {
System.out.println(service);
}
}
The last message in my logs is
DEBUG::WELD-000100: Weld initialized. Validating beans
Content of src/test/resources/META-INF/beans.xml:
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
</beans>
By the way I tried the cdi-unit library and it works, but I need to use my own WeldJUnit4Runner which is currently:
public class WeldJUnit4Runner extends BlockJUnit4ClassRunner {
private final Weld weld;
private final WeldContainer container;
public WeldJUnit4Runner(Class<?> klass) throws InitializationError {
super(klass);
this.weld = new Weld();
this.container = weld.initialize();
}
#Override
protected Object createTest() throws Exception {
return container.instance().select(getTestClass().getJavaClass()).get();
}
}
I use weld-se 2.4.1.Final for testing.
Thanks.
EDIT:
So it seems like Weld only looks into src/test/java (when I copy SomeService over to src/test/java it woks). This is silly, I am not going to duplicate all my classes to test them... How to tell Weld to retrieve classes from src/main/java?
So I was able to make it work by creating src/main/resources/META-INF/beans.xml in addition to the existing src/main/webapp/WEB-INF/beans.xml and src/test/resources/META-INF/beans.xml meaning now I have 3 times the exact same file in the same project which I find silly but I guess this is how it is in the Weld world...
Thanks all for your time.
EDIT:
Actually I am able to deploy the application with only src/main/resources/META-INF/beans.xml (I removed src/main/webapp/WEB-INF/beans.xml)
Sorry, I have no solution, but only a small clue: if you want to do some customizations of the BlockJUnit4ClassRunner - why don't you try to extend the org.jglue.cdiunit.CdiRunner or org.apache.deltaspike.testcontrol.api.junit.CdiTestRunner? Or at least take a look at their source code.
Ps. I always find Weld's class-path scanning brittle & error prone. And try to avoid it as much as possible.
It should work so I post here what I did.
Firstly, I use :
Eclipse Luna
JDK 7
The tree of my project is the following one :
Here are my pom dependencies :
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se-core</artifactId>
<version>2.4.1.Final</version>
<scope>test</scope>
</dependency>
The SomeService interface :
package org.jvi.cdirunner;
public interface SomeService {
void test();
}
The SomeServiceImpl implementation :
package org.jvi.cdirunner;
public class SomeServiceImpl implements SomeService {
#Override
public void test() {
// TODO Auto-generated method stub
}
}
And the test to run :
package org.jvi.cdirunner.test;
import javax.inject.Inject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.jvi.cdirunner.SomeService;
#RunWith(WeldJUnit4Runner.class)
public class SomeServiceIT {
#Inject
private SomeService service;
#Test
public void test() {
System.out.println(service);
}
}
And everything works fine if I run the test under Eclipse. I can't figure out why it doesn't work on your side.

#inject does not work with stateless EJB

Hi I have a very simple example. I created a resource in javaee 7 as follows:
#Path("greetings")
public class GreetingsResource {
#Inject
Sample s;
#GET
public JsonObject greetings(){
return Json.createObjectBuilder().add("first","1")
.add("second","2")
.add("third","3")
.add("fourth","4")
.add("helloworld", s.helloWorld())
.build();
}
}
Sample is the following simple EJB:
#Stateless
public class Sample {
public String helloWorld(){
return "Hello World";
}
}
Finally the resource Application class:
#ApplicationPath("resources")
public class RestConfiguration extends Application {
}
I can access the URL: "localhost:8081/jasonandjaxrs/resources/greetings"
The problem is that #Inject gives the following error:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=sample,parent=GreetingsResource,qualifiers={}),position=-1,optional=false
But #EJB seems to work. I am trying to understand why #Inject does not work? Thank you.
You can't use CDI (means #Inject) with this setup. CDI only works with beans managed by the container which is not the case for JAX-RS resource classes (your GreetingsResource).
JAX-RS 2.0 does not support injection of EJBs into JAX-RS components
(providers, resources).
If you use #Inject in your case the injection is provided by the HK2 dependency injection framework which isn't aware of normal CDI beans. It even shouldn't work if you use #EJB, I don't know why it works, maybe this has to do with Java EE 7.
As it works for you there should be no problem in using #EJB here, but there are also some alternative approaches in my response to this question.
See also:
Inject a EJB into JAX-RS (RESTfull service)
JERSEY-2040 Add support for injection of EJBs into Jersey-managed providers and resources