injecting named service in JAX-RS resource by constructor with OpenEJB - jax-rs

I'm using OpenEJB as application server and I want to deploy a Jax-RS resource that requires some named service to be injected in its constructor.
My resource looks like :
#Singleton
#Path("/")
public class Resource {
private Service service;
#Inject
public Resource(#Named("service") Service service) {
this.service = service;
}
}
Unfortunately, OpenEJB complains because it doesn't consider my constructor to be valid because of the #Named annotation decorating the Service argument.
java.lang.RuntimeException: Resource class class test.Resource has no valid constructor
at org.apache.openejb.server.cxf.rs.CdiResourceProvider.validateConstructorExists(CdiResourceProvider.java:138)
at org.apache.openejb.server.cxf.rs.CdiResourceProvider.<init>(CdiResourceProvider.java:100)
at org.apache.openejb.server.cxf.rs.OpenEJBPerRequestPojoResourceProvider.<init>(OpenEJBPerRequestPojoResourceProvider.java:28)
at org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication(CxfRsHttpListener.java:522)
The implementation of the OpenEJB CdiResourceProvider clearly doesn't want something else than the Jax-RS #Context annotation for constructor arguments...
Is it supported by OpenEJB?

JAX-RS has a specific requirement for a no-args constructor. This will be true of any JAX-RS impl, its not specific to the OpenEJB integration.

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

Ninject interception WCF service

I'm a newbie on the subject, so I'll try to make this as clear as I can...
I created a WcfModule, where I load the following package:
Bind<IDistributorService>().To<DistributorService>().InRequestScope().Intercept().With<ExceptionInterceptor>();
At first, I don't receive any error, but I put an InterceptAttribute on my function:
[AttributeUsage(AttributeTargets.Method)]
public sealed class HandleExceptionsAttribute : InterceptAttribute
{
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
return request.Kernel.Get<ExceptionInterceptor>();
}
}
[HandleExceptions]
public virtual Result<List<DistributorDataContract>> GetDistributor(string id)
{
//...code...
I get an error in this function: (first line in method)
private ServiceHost CreateNewServiceHost(Type serviceType, Uri[] baseAddresses, WebHttpBehavior webBehavior, WebHttpBinding webHttpBinding)
{
var host = base.CreateServiceHost(serviceType, baseAddresses);
//...
}
With the error:
InvalidProxyConstructorArgumentsException was unhandled by user code
Can not instantiate proxy of class:
My.Namespace.DistributorService.
Could not find a parameterless constructor.
Anyone who knows what the problem could be? Thanks!
This exception is thrown by castle core dynamic proxy when it is instructed to create a "class proxy" which does not have a parameterless (default) constructor and no constructor-arguments are passed to castle (see source).
My best guess is, that when you use ninject interception by attributes, ninject will instruct castle core to create a class-proxy, no matter whether your binding is Bind<IFoo>().To<Foo>() or Bind<Foo>().ToSelf().
It seems a bit strange, however, that ninject is not resolving and passing along all required constructor parameters.
What is the implementation of DistributorService and what's the implementation of the base class of the class containing CreateNewServiceHost?
Workaround:
Of course, switching to the Intercept().With<TInterceptor>() syntax will probably also enable you to use interception (see http://codepyre.com/2010/03/using-ninject-extensions-interception-part-2-working-with-interceptors/)

Injecting #EJB in OmniFaces #Eager bean causes "Severe: No valid EE environment for injection of org.omnifaces.cdi.eager.EagerBeansRepository"

Using #ApplicationScoped #Named #Eager, my #EJB-injected #Stateless beans are not properly instantiated and evaluate to null.
I had an #ApplicationScoped #ManagedBean(eager=true) that was used to schedule a few jobs. Some #Stateless beans were injected using #EJB annotation, and that worked fine.
In the move to CDI annotations, I added the OmniFaces #Eager annotation as substitute for #ManagedBean(eager=true) which is missing in standard CDI:
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.EJB;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.omnifaces.cdi.Eager;
#Named
#ApplicationScoped
#Eager
public class MyScheduler implements Serializable {
#EJB
private MyService myService;
#Inject
private MyNamedBean myNamedBean;
#PostConstruct
public void init() {
setupSchedulers();
}
#PreDestroy
public void destroy() {
destroySchedulers();
}
//...
}
Using this setup, the #PostConstruct method is correctly called on application startup (though it seems to run even before the context is initialized), but then myService evaluates to null.
In the log, the following warnings appear:
Severe: No valid EE environment for injection of org.omnifaces.cdi.eager.EagerBeansRepository
Severe: No valid EE environment for injection of my.package.MyScheduler
Info: Initializing Mojarra 2.2.8 ( 20140814-1418 https://svn.java.net/svn/mojarra~svn/tags/2.2.8#13507) for context '/tagific'
Since I need to access this bean from other ones, I couldn't use the #Singleton and #Schedule annotations.
How could I properly inject #Stateless beans in an #Named applications scoped bean that would be instantiated on application startup?
This looks like an initialization ordering bug in GlassFish. The #Eager #ApplicationScoped runs in a ServletContextListener. Apparently at that point GlassFish hasn't EJBs ready for injection. This construct works in e.g. WildFly.
However, in CDI's name of unifying various different depency injection approaches throughout Java EE, you can also just use #Inject instead of #EJB. The CDI proxy is capable of delegating further to the right #Stateless instance.
#Inject
private MyService myService;
You can also use #Inject inside EJBs itself, but as of now (Java EE 7) it doesn't yet support self-referencing for e.g. #Asynchronous methods. For that you have still to stick to #EJB.
That said, are you aware that Oracle stopped commercial support on GlassFish and that you'd better not use it for production environments? See also this blog.

#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