Is it possible to add an instance of singleton framework to CDI context? - singleton

I'm trying to integrate StarMX framework (https://github.com/rogeriogentil/starmx) into a legacy web application. This framework uses JMX techonology and is initialized using the Singleton pattern: StarMXFramework.createInstance(). The web application uses Java EE 6 technologies such as EJB and CDI (also DeltaSpike). However, the way the framework is being initialized (code below) doesn't add its instance to the CDI context.
import org.starmx.StarMXException;
import org.starmx.StarMXFramework;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Singleton;
import javax.ejb.Startup;
#Startup
#Singleton
public class StarMXSingleton {
private StarMXFramework starMX;
#PostConstruct
public void postConstruct() {
try {
starMX = StarMXFramework.createInstance();
} catch (StarMXException e) {
(...)
}
}
#PreDestroy
public void preDestroy() {
if (starMX != null) {
try {
starMX.shutdown();
} catch (StarMXException e) {
(...)
}
}
}
}
I know that is possible to extend CDI, but is it possible to add an instance of singleton framework to CDI context?

There are two ways, first and easy one is a producer. Here is a link to what CDI producers are and how they work. In short, CDI will use this producer to create the instance of a bean whose types are mandated by the return type of the producer method.
The producer method has to be placed inside a CDI bean so that is it picked up by CDI. Note that the scope of the producer affects how often it will be invoked, just as it would be with standard bean. Here is how it could look like:
#ApplicationScoped
public class SomeCdiBeanInYourApplication {
#Produces //denotes producer method
#ApplicationScoped // scope of produced bean, use CDI scope (the singleton you have is EJB annotation)
public StarMXFramework produceMxFramework() {
return StarMXFramework.createInstance();
}
}
Second means is then CDI extension, namely a lifecycle observer for AfterBeanDiscovery event where you can addBean(). Here is a link to CDI 2.0 spec, feel free to browse older versions based on what version you are on.
I won't write code for that as it is rather complex and long, the producer should do the trick for you.
See also
Please explain the #Produces annotation in CDI

Related

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

Java EE - dependency injection into batchlet

I am having issues with dependency injection in a batchlet.
#Named
public class SimpleBatchlet extends AbstractBatchlet {
#Inject
protected StorageService storageService;
...
public String process() throws Exception {
storageService.doSomething(); // this throws a null pointer exception
}
}
#Named
public class LocalFileStorageService implements StorageService {
public void doSomething() {
}
}
I have tried putting beans.xml in both META-INF and WEB-INF and removing it, all to no avail. I also tried changing the scopes of the beans to singletons, etc. I am invoking / starting the batch job through the use of an #Schedule annotation on a method that uses BatchRuntime to start the job.
I must be missing something simple as I know this should work. The actual scope of the beans I will use may need to vary, but the point I am trying to make is that I don't believe bean scope is a problem, but some other configuration issue.
I should also note that I only have 1 implementation of StorageService.
Not clear what really is your problem (NPE on injected CDI bean?), but annotating your Batchlet #Dependent should solve the problem :
#Named
#Dependent
public class SimpleBatchlet extends AbstractBatchlet {
#Inject
protected StorageService storageService;
}
Batchlet need to be #Named and #Dependent for integration with CDI.

Inject EJB into JAX-RS 2.0 subresource when subresource is got via ResourceContext

I am using Jersey 2.8 with Glassfish 4.0.
I have a resource locator class which looks like below
#Path("/")
#ManagedBean
public class MyServiceLocator {
#Context
ResourceContext rc;//javax.ws.rs.container.ResourceContext
#EJB
private MyEJBHome myEJB;
#Inject//javax.inject.Inject
MySubService mss;
#Path("/mysubservice")
public MySubService getMySubService() {
return rc.getResource(MySubService.class);
//also tried return rc.initResource(new MySubService());
}
}
and a sub resource class which is
#ManagedBean
public class MySubService {
#EJB
public MyEJBHome myEJB;
#Context
HttpHeaders heads;
/*#Inject
private myEJBHome myEJB2;*/
#Path("/mypath")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Object doSomething(#Context SecurityContext securityContext) {...}
}
beans.xml file is put to META-INF and WEB-INF.
In MyServiceLocator class private MyEJBHome myEJB is injected successfully. And MySubService mss object is injected successfully and with EJB injected into it.
The problem is that when MySubService is got via ResourceContext the EJB is not injected into it.
Previously i used Glassfish 3 and Jersey 1.17 with proprietary ResourceContext and absolutely the same code worked ok.
I googled a lot and read a lot of similar (but a bit different) questions and as i understood non JAX-RS stuff (EJB in my case) can't be injected when sub resource is got via ResorceContext. Is it true? If yes how can i work it around?
The one possible solution is to inject sub resource objects to the resource locator class but there are too many of them and it seems to be very ugly.
EDIT Injection with #Inject works if to create a binder, bind ejb class to ejb interface and register that binder. But i don't want to describe binding for hundreds of my ejbs. Also as i understand it is specific binding fir HK2 system and i don't want to be linked to it.
Different actions with setting #Named annotations and trying to inject via CDI didn't help. It seems that when getting sub-resource via ResourceContext Jersey uses only HK2 and that's why CDI can't do it's work. Is that correct?
The only appropriate solution i found was to create my own annotation and inject provider.
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface EJBInject {
String beanName();
}
#Provider
public class EjbInjectProvider implements InjectionResolver<EJBInject> {
#Override
public Object resolve(Injectee injectee, ServiceHandle<?> handle) {
try {
String beanName = injectee.getParent().getAnnotation(EJBInject.class).beanName();
return new InitialContext().lookup("java:global/MyApp/" + beanName);
} catch (Exception e) {
return null;
}
}
#Override
public boolean isConstructorParameterIndicator() {
return false;
}
#Override
public boolean isMethodParameterIndicator() {
return false;
}
}
Then ejb can be injected using that annotation like
#EJBInject(beanName="MyBean")
MyBeanEJBHome myBean;
In such case any standard EJB injections which MyBeanEJBHome might need work correctly, too.

#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

Dozer DozerBeanMapper Instantiation Startup EJB App Server Glassfish

Dozer's documentation states that you should only have one instance of DozerBeanMapper running in the app on the server. For initial development I ignored this, now I want to update the app to do this.
How can I instantiate the DozerBeanMapper class when the application starts on glassfish, and how would I access its "map" method in another class once the application has started or been newly deployed?
This is for EJBs so I can't use any servlet to do this.
OK, so I've finally had time to refactor this code. With the pointer from #Mikko Maunu, I am editing my question to provide the code that I have working for me for anyone who might find it useful in the future.
package com.xyz.utilities.singleton;
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import org.dozer.DozerBeanMapper;
#Startup
#Singleton
public class DozerInstantiator {
private DozerBeanMapper mapper = null;
#PostConstruct
void init() {
mapper = new DozerBeanMapper();
}
public DozerBeanMapper getMapper() {
return mapper;
}
}
And here is a straight forward usecase:
Inject an EJB member variable to your client class:
#EJB
DozerInstantiator di;
Within a method somewhere in the client class you can invoke the dozer mapper like so:
Credentials credentials = di.getMapper().map(credentialsDTO, Credentials.class);
// or
Credentials credentials = new Credentials();
di.getMapper().map(credentialsDTO, credentials);
If this is wrong or off base, someone please leave a comment. Until then, this seems to work so I'll use this solution I've developed with Mikko's input.
If you are using GlassFish 3.x, then you can use EJB 3.1 Singleton Session Bean:
#Startup //initialization in application startup
#Singleton //only one instance
public class DozerInitializer {
private String status;
#PostConstruct //executed once and only once when sole instance is created
void init {
//do steps needed to instantiate DozerBeanMapper
//here
}
}