I've been searching for hours to find a solution for my problem but I can't get it to work. I want to inject my Weld-managed service into a ConstraintValidator that is used to validate a User-Object that is posted to my JAX-RS Rest-Service. Everything is deployed to a glassfish 4.1 server.
I have a Service like this
#ApplicationScoped
public class UserService {
}
and I want to inject it into a ConstraintValidator like this
public class UniqueUserNameValidator implements ConstraintValidator<UniqueUserName, ApiUser> {
#Inject
private UserService service;
#Override
public void initialize(UniqueUserName constraintAnnotation) {
}
#Override
public boolean isValid(ApiUser value, ConstraintValidatorContext context) {
return service.getByUserName(value.getUserName()) == null;
}
}
the REST resource looks like this
#Path("users")
#Produces(MediaType.APPLICATION_JSON)
public class UserResource {
#Inject
UserService userService;
#POST
public Response createUser(#Valid ApiUser apiUser) {
ApiRepresentation created = userService.create(apiUser);
return Response.created(createURL(created)).build();
}
}
When I Post a json user object i get the following exception:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=UserService,parent=UniqueUserNameValidator,qualifiers={},position=-1,optional=false,self=false,unqualified=null,173822971)
at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74)
at org.jvnet.hk2.internal.Utilities.justInject(Utilities.java:947)
at org.jvnet.hk2.internal.ServiceLocatorImpl.inject(ServiceLocatorImpl.java:902)
at org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:977)
at org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:968)
at org.glassfish.jersey.internal.inject.Injections.getOrCreate(Injections.java:173)
I'm aware that jersey uses hk2 as DI provider and the ConstraintValidator is created using the InjectingConstraintValidatorFactory which in return uses the ResourceContext. Since HK2 doe know nothing about my WELD container managed beans it can not inject the proper service when creating the ConstraintValidator.
To fix this I am searching for
a) A way to provide JAX-RS (preferable a pure JAX-RS way without a dependency to jersey) with a custom ConstraintValidatorFactory to create the validator.
or
b) A way to force jersey to use WELD as the DI provider or tell hk2 to pickup all container managed beans WITHOUT manually adding every single bean to hk2.
I have no Idea how to use the bridge proposed here .
I appreciate any help.
Cheers
I also faced this issue with Jersey 2.25.x, Weld 2.4.x and Tomcat 8.x and haven't found a proper solution with #Inject.
As a workaround, I programmatically looked up for the bean instance using:
SomeSortOfBean bean = CDI.current().select(SomeSortOfBean.class).get();
Do you have the possibility to change the underlying JAX-RS implementation for your project?
When I had the same problem, I just switched from Jersey to RestEasy (fully certified JAX-RS implementation). http://resteasy.jboss.org/
Changing the implementation was easy enough: Just include the dependy through your favorite build automation tool (I use gradle):
compile 'org.jboss.resteasy:resteasy-servlet-initializer:3.0.11.Final'
Additionally, to make CDI work, include the resteasy-cdi JAX-RS CDI bridge:
compile 'org.jboss.resteasy:resteasy-cdi:3.0.11.
Lastly if you want the same JSON format, include the resteasy-jackson-provider:
compile 'org.jboss.resteasy:resteasy-jackson-provider:3.0.11.Final'
In the end, switching to resteasy gave me a lot less headache than trying to implement a Jersey fix.
Related
I have an application that uses Jersey/JAX-RS for web services (annotations, etc) and Guice to inject service implementations. I don't really like the way Guice works with servlets directly, I prefer the Jersey way, so I had to do a bit of fussing to get the service injections to work since Guice wouldn't be creating my servlet classes, and I didn't want to deal with the HK2-Guice bridge. I did this by creating a listener class (called Configuration) that sets up the injectors in static fields upon application startup and then manually effecting the injections in each servlet class by creating a parent class that all my servlets extend with a constructor that contains the following:
public MasterServlet() {
// in order for the Guice #Inject annotation to work, we have to create a constructor
// like this and call injectMembers(this) on all our injectors in it
Configuration.getMyServiceInjector().injectMembers(this);
Configuration.getDriverInjector().injectMembers(this);
}
I know it's kind of hacky, but this works just fine in my servlets. I can use the Guice #Inject annotations on my services and switch between named implementations and so on. The problem comes when I go to set up my unit tests. I'm using JerseyTest to do my tests, but running a test against my servlets results in a 500 error with Guice saying the following:
com.google.inject.ConfigurationException: Guice configuration errors:
1) No implementation for com.mycompany.MyService was bound.
while locating com.mycompany.MyService
for field at com.mycompany.servlet.TestGetServlet.service(TestGetServlet.java:21)
while locating com.mycompany.servlet.TestGetServlet
The test looks like this:
public class TestServletTest extends JerseyTest {
#Test
public void testServletFunctional() {
final String response = target("/testget").request().get(String.class);
assertEquals("get servlet functional", response);
}
#Before
public void setup() {
Configuration configuration = new Configuration();
configuration.contextInitialized(null);
}
#Override
protected Application configure() {
return new ResourceConfig(TestGetServlet.class);
}
}
You'll notice in the setup method I am manually creating my Configuration class since I can't rely on the test container (Grizzly) to create it (I get NullPointerExceptions without those two lines). More about this below.
And here's the servlet being tested:
#Path("/testget")
public class TestGetServlet extends MasterServlet {
#Inject
MyService service;
#GET
#Produces({"text/plain", MediaType.TEXT_PLAIN})
public String testGet() {
//service = Configuration.getServiceInjector().getInstance(MyService.class);
return "get servlet functional";
}
}
Notice the commented line in the testGet() method? If I do that instead and remove the #Inject annotation above, everything works fine, which indicates that Grizzly is not creating my servlets the way I expect.
I think what's happening is that Grizzly doesn't know about Guice. Everything seems to suggest that Grizzly isn't seeing the Configuration class, despite the fact that by putting it in my test's #Before method it seems to be at least available to the classes that use it (see: the commented line in the TestGetServlet class). I just don't know how to fix it.
I'm still trying to figure this out but in the meantime I switched from Guice to HK2, which took a bit of doing but I figured this might be helpful for anyone who runs into this problem in the future.
I consider this an answer because truthfully my attempt to bypass the Guice-HK2 bridge but still use Guice with Jersey might not have been the best idea.
Switching from Guice to HK2 takes a bit of doing and there's no comprehensive guide out there with all the answers. The dependencies are really fussy, for example. If you try to use Jersey 2.27 you may run into the famous
java.lang.IllegalStateException: InjectionManagerFactory not found
error. Jersey 2.27 is not backwards compatible with previous versions due to HK2 itself. I am still working on getting that all to work, but in the meantime I had to downgrade all my Jersey dependencies to 2.26-b06 to get HK2 working properly.
Jersey thankfully already implements a bunch of HK2 boilerplate, so all you need to get injection working is proper use of #Contract, #Service (see HK2 docs for those), and then two new classes that look like this:
public class MyHK2Binder extends AbstractBinder {
#Override
protected void configure() {
// my service here is a singleton, yours might not be, so just omit the call to in()
// also, the order here is switched from Guice! very subtle!
bind(MyServiceImpl.class).to(MyService.class).in(Singleton.class);
}
}
And this:
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
register(new MyHK2Binder());
packages(true, "com.mycompany");
}
}
Simple enough, but this only works for the application itself. The test container knows nothing about it, so you have to redo the Binder and ResourceConfig yourself in your test class, like this:
public class TestServletTest extends JerseyTest {
#Test
public void testServletFunctional() {
final String response = target("/testget").request().get(String.class);
assertEquals("get servlet functional", response);
}
#Before
public void setup() {
}
#Override
protected Application configure() {
return new TestServletBinder(TestGetServlet.class);
}
public class TestServletBinder extends ResourceConfig {
public TestServletBinder(Class registeree) {
super(registeree);
register(new MyHK2Binder());
packages(true, "com.mycompany");
}
}
}
Having to do this is actually fine because you can switch out the Binder for a test binder instead, in which you've bound your service to a mocked service instead or something. I haven't done that here but that's easy enough to do: replace new MyHK2Binder() in the call to register() with one that does a binding like this instead:
bind(MyTestServiceImpl.class).to(MyService.class).in(Singleton.class);
And voila. Very nice. Obviously you could achieve a similar result with Named bindings, but this works great and might even be simpler and more clear.
Hope this helps someone save the hours I spent screwing around to get this working.
I used to integrate Service and DAO beans in Jersey REST resources by annotating them with #Path following Java EE tutorial
In general, for JAX-RS to work with enterprise beans, you need to annotate the class of a bean with #Path to convert it to a root resource class. You can use the #Path annotation with stateless session beans and singleton POJO beans.
So my code used to be something like this:
#Path("/")
public class ServiceResource {
#Inject
private AccountService accountService;
#GET
#Path("/account/get")
public Account getAccount(#QueryParam("id") String id) {
return accountService.get(id);
}
}
#javax.inject.Singleton
#Path("")
public class AccountService {
public Account get(String id){...}
}
Now, I started integrating a Quartz Job into my application, and I wanted to find a way to inject my AccountService inside a job like this
public class AccountJob implements Job {
#Inject
private AccountService accountService;
#Override
public void execute(JobExecutionContext jec) throws JobExecutionException {
accountService.updateAllAccounts();
}
}
I found this answer that tells to use DeltaSpike to do the Job, so I added the following dependencies to my pom.xml, and without adding any more lines of code to any class the inejection of accountService to my Job works fine
<dependency>
<groupId>org.apache.deltaspike.modules</groupId>
<artifactId>deltaspike-scheduler-module-api</artifactId>
<version>1.7.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.deltaspike.modules</groupId>
<artifactId>deltaspike-scheduler-module-impl</artifactId>
<version>1.7.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.deltaspike.cdictrl</groupId>
<artifactId>deltaspike-cdictrl-api</artifactId>
<version>1.7.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.deltaspike.cdictrl</groupId>
<artifactId>deltaspike-cdictrl-weld</artifactId>
<version>1.7.2</version>
<scope>runtime</scope>
</dependency>
However, I realized that when I remove the #Path("") from AccountService, its instance is still injected fine inside ServiceResource, so my questions are the following:
Why adding DeltaSpike dependencies made it possible to inject my beans without using #Path on them?
By searching more, I understood that DeltaSpike internally uses Weld to do the injection, and since I am already using GlassFish 4.0, I know that Weld is already there, so why the injection is not working by default in my Job class and in ServiceResource class without adding #Path on my beans? Actually why adding #Path is even suggested in the Java tutorial?
Is there any bad side effects that I don't see in my code, because I think that I am mixing multiple DI methods here without really understanding how do they work?
Update: After more search, I realize that Jersey doesn't use Weld for dependency injection, instead it uses HK2, a different framework that also happens to be a part of GlassFish, when I try to inject AccountService without using #Path it shows the following exception
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=AccountService,parent=ServiceResource,qualifiers={}...
So this updates the questions to the following:
How to make HK2 injections works? // Without using #Path as mentioned in the Java EE Tutorial
If I managed to to do DI with HK2, will it be safe to use DeltaSpike to do DI for the Quartz Job? Is it okay to mix two CDI framewroks together to scan the classes and do the injection?
I put my my source code on pastebin; pom.xml is here and the Java is here
You do not need to set the Path annotation on your AccountService CDI bean. If CDI is enabled on your application (either with empty beans.xml in CDI 1.0 or discovery-mode=all in CDI > 1.0), you can #Inject any CDI bean in your JAX-RS resource.
So you just have to write the following class:
#Path("/")
public class ServiceResource {
#Inject
private AccountService accountService;
#GET
#Path("/account/get")
public Account getAccount(#QueryParam("id") String id) {
return accountService.get(id);
}
}
#javax.inject.Singleton
public class AccountService {
public void Account get(String id){...}
}
The article you linked in your post deals with mixing EJB and CDI annotations. For example you can mix #Stateless and #Path annotations. It's interesting for example because you can :
Benefit of EJB transaction in your Rest resource (even if now you can use #Transactional interceptor binding)
Set a pool of resources
etc.
Note that all of this works without the help of deltaspike dependency.
For your second question, as Quartz manages its own threads, classes are not handled by CDI so you can not inject beans in Quartz classes. The aim of the deltaspike module is to allow injecting CDI beans in Quartz Jobs. Internally, deltaspike controls CDI Contexts.
EDIT
For your last questions:
Your HK2 problem comes pretty sure from a missing dependency (in your application or server). As said in a previous comment, I managed to deploy your App on Glassfish 4 (build 89) with the source files you provided.
Regarding the integration of CDI with Quartz, I think the best is to implement your own JobFactory and instanciate your jobs using BeanManager. Take a look at this link : https://devsoap.com/injecting-cdi-managed-beans-into-quarz-jobs/
First of all injected resources(beans) and Jersey Endpoint class(point of injection) must be CDI-Aware. It must be detecteable by CDI. We can use bean-discovery-mode="all" - then CDI scan ALL classes or
bean-discovery-mode="annotated" and MARK our class with PROPER annotation: from here : Bean defining annotations. I prefer#Dependent or #RequestScoped
Then we must use Jersey Extension
<dependency>
<groupId>org.glassfish.jersey.ext.cdi</groupId>
<artifactId>jersey-cdi1x-servlet</artifactId>
<version>{version}</version>
<scope>runtime</scope>
</dependency>
`
to connect CDI with HK2 discovery mechanism.
Here is Official oracle Guideline
The default beans.xml discovery-mode (in Java EE 7) is "annotated". Which means only beans that have CDI annotations are recognized and managed by CDI.
Your AccountJob class is not annotated. If you want CDI to be able to inject the service into it then you need to annotate it with some scope annotation, e.g. #ApplicationScoped.
Your other option is to create CDI producer for creating AccountJob beans. See:
http://docs.jboss.org/weld/reference/latest/en-US/html_single/#_producer_methods
I like to build a REST server that uses dependency injection. In my case the requirements would be
1) Not the services shall be injected, but the dependency they use
2) The services should be discovered via ServiceLoad and not written predefined in the web.xml
As an example:
I have the following project structure
project-base
contains the API, such as TheServiceInterface and TheDaoInterface
project-service-plugin
A plugin - contains a service implementation like
Path("foo")
public class TheService implements TheServiceInterface {
private TheDaoInterface dao;
#Inject
public TheService(TheDaoInterface dao) {
this.dao = dao;
}
#POST
#Consumes(APPLICATION_JSON)
#Path("pr")
public void webmethod(String request) {
// do something with the request and dao
}
}
project-integration
Wiring things together. The idea here is to find all TheServiceInterface implementations via ServiceLoader and inject the dao implementation into them.
I tried Jersey and Guice: a perfect combination for writing RESTful APIs, but this uses Jersey 1 and it seems that Jersey 2 and Guice have some problems, or all examples I find is only where the services are injected or written in the web.xml
Is my approach possible - and if so how ? What technologies can be used of achieving it ?
If there is a framework helping or another jvm language like groovy, please let me know
Thanks
I have this scenario where i have my EJB3 beans in a jar file, deployed successfully to Jboss EAP-6.4.
Then I have another web project that looks up these EJB's inside a REST POJO class. I can currently access the EJB's from inside the web project using #Inject and #EJB, but my use case is one that i don't know which beans i need to load until runtime and the list is not static, so i might need to lookup 10 EJB's or none for a particular request etc.
I know I can possibly use
InitialContext.lookup('ejb:/.....')
to retrieve my EJB beans from inside the web project, but is there a way that i can retrieve them without that round trip(i believe), or maybe what am just looking for is a more elegant way to do EJB look-up at runtime just like the statically typed #EJB and #Inject versions.
Any suggestions are greatly appreciated.
EDIT
In my REST POJO classes i don't want to hard code any #Inject or #EJB annotations, rather i want that when a request comes in i look-up(for lack of better word) the EJB's that will handle the request, so all the decision is made at runtime really, as shown below
#Path("/path")
public class TestService {
#GET("/{id}")
public String loadGetPath(#Param id int id){
//at this point i want to dynamically resolve the EJB based on
//the value of id
}
}
Whoopdicity blog: Developing a dynamic JEE service client with CDI seems to have what you are looking for. At the end it claims you can do:
public class MyServiceConsumer {
#Inject #ServiceClient
private MyBusinessService service;
...
}
Instead of
public class MyServiceConsumer {
#EJB(lookup="...")
private MyBusinessService service;
...
}
I have an ExceptionMapper defined as following
#Provider
public class MyExceptionMapper implements ExceptionMapper<Throwable> {
#Inject
private Manager myManager;
#Override
public Response toResponse(Throwable exception) {
// My implementation
}
}
Deploying this code on glassfish 4 results with exception:
org.glassfish.hk2.api.UnsatisfiedDependencyException:
There was no object available for injection at
Injectee(requiredType=Manager,parent=MyExceptionMapper,qualifiers {}),position=-1,optional=false,self=false,unqualified=null,955636053)
When I use #Context instead of #Inject I do not see the exception but myManager is null
I tried making MyManager as #ManagedBean, #Singleton or an EJB (Stateless, Singleton) and non works
In JEE6 (with glassfish 3) you have to add
#javax.annotation.ManagedBean
to the provider implementation. Possibly this works also for Glassfish 4
As far as I know, this issues comes from the following. CDI is not in place to manage the dependencies of restful services and providers by default. But when adding #ManagedBean you enable CDI to create the instance.
Here is an example where I introduced CDI to a restful service using jersey.
You can follow the updates regarding this issue here https://java.net/jira/browse/JERSEY-2393
You could use OmniFaces Beans to get a CDI managed bean instance in your ExceptionMapper:
Beans.getInstance(Bean.class)
I'm using this with #javax.ejb.Stateless beans containing #javax.persistence.PersistenceContext.