I'm trying to inject a Stateless EJB into my JAX-RS webservice via annotations. Unfortunately the EJB is just null and I get a NullPointerException when I try to use it.
#Path("book")
public class BookResource {
#EJB
private BookEJB bookEJB;
public BookResource() {
}
#GET
#Produces("application/xml")
#Path("/{bookId}")
public Book getBookById(#PathParam("bookId") Integer id)
{
return bookEJB.findById(id);
}
}
What am I doing wrong?
Here is some information about my machine:
Glassfish 3.1
Netbeans 6.9 RC 2
Java EE 6
Can you guys show some working example?
I am not sure this is supposed to work. So either:
Option 1: Use the injection provider SPI
Implement a provider that will do the lookup and inject the EJB. See:
#EJB injection.
Example for com.sun.jersey:jersey-server:1.17 :
import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.core.spi.component.ComponentScope;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;
import javax.ejb.EJB;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.ws.rs.ext.Provider;
import java.lang.reflect.Type;
/**
* JAX-RS EJB Injection provider.
*/
#Provider
public class EJBProvider implements InjectableProvider<EJB, Type> {
public ComponentScope getScope() {
return ComponentScope.Singleton;
}
public Injectable getInjectable(ComponentContext cc, EJB ejb, Type t) {
if (!(t instanceof Class)) return null;
try {
Class c = (Class)t;
Context ic = new InitialContext();
final Object o = ic.lookup(c.getName());
return new Injectable<Object>() {
public Object getValue() {
return o;
}
};
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
Option 2: Make the BookResource an EJB
#Stateless
#Path("book")
public class BookResource {
#EJB
private BookEJB bookEJB;
//...
}
See:
How to Combine REST Services with EJB 3.1
EJB 3.1 And REST - The Lightweight Hybrid
Option 3: Use CDI
#Path("book")
#RequestScoped
public class BookResource {
#Inject
private BookEJB bookEJB;
//...
}
See:
Injecting an EJB from a jar into a jax-rs class in a war
This thread is rather old, nevertheless i fought the same problem just yesterday. Here is my solution:
Just make the BookResource a managed bean through #javax.annotation.ManagedBean at class level.
For this to work you need to enable CDI with a beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>
This file needs to be in WEB-INF if the BookResource is part of a war file. If the BookResource is packaged with the ejbs put it into META-INF.
If you want to use #EJB you're done. If you want to inject the EJB through #Inject than a beans.xml must be put into the ejbs jar file into META-INF as well.
What you're doing: You're just telling the container that the resource should be container managed. Therefor it supports injection as well as lifecycle events. So you have your business facade without promoting it to an EJB.
You don't need to extend javax.ws.rs.core.Application for this to work. BookResource is as a root resource automatically request scoped.
Tested with Glassfish 3.1.2 and a maven project.
Happy coding.
You shall be able to do injection in JAX-RS resource without making it EJB or CDI component. But you have to remember that your JAX-RS resource must not be singleton.
So, you setup your application with this code. This makes BookResource class per-request JAX-RS resource.
#javax.ws.rs.ApplicationPath("application")
public class InjectionApplication extends javax.ws.rs.core.Application {
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> classes = new HashSet<Class<?>>();
public InjectionApplication() {
// no instance is created, just class is listed
classes.add(BookResource.class);
}
#Override
public Set<Class<?>> getClasses() {
return classes;
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}
With this setup, you are letting JAX-RS to instantiate BookResource for you on per-request basis and also inject all the required dependencies. If you make BookResource class singleton JAX-RS resource, this is, you put in getSingletons
public Set<Object> getSingletons() {
singletons.add(new BookResource());
return singletons;
}
then, you created instance which is not managed by JAX-RS runtime and nobody in container cares to inject anything.
Unfortunately, my answer is too long for a comment, so here goes. :)
Zeck, I hope that you are aware of what exactly you are doing by promoting your bean to an EJB, as suggested by Pascal. Unfortunately, as easy as it is nowadays with Java EE to 'make a class an EJB', you should be aware of the implications of doing so. Each EJB creates overhead along with the additional functionality it provides: they are transaction aware, have their own contexts, they take part in the full EJB life cycle, etc.
What I think you should be doing for a clean and reusable approach is this: extract the access to your servers services (which hopefully are accessed through a SessionFacade :) into a BusinessDelegate. This delegate should be using some kind of JNDI lookup (probably a ServiceLocator - yes, they are still valid in Java EE!) to access your backend.
Okay, off the record: if you really, really, really need the injection because you do not want to write JNDI access manually, you could still make your delegate an EJB, although it ... well, it just feels wrong. :)
That way at least it will be easy to replace it later with something else if you do decide to switch to a JNDI lookup approach...
I was trying to do the exact same thing. I'm using EJB 3.1 and have a deployed my app as an EAR with separate EJB project. As Jav_Rock pointed out, I use context lookup.
#Path("book")
public class BookResource {
#EJB
BookEJB bookEJB;
public BookResource() {
try {
String lookupName = "java:global/my_app/my_ejb_module/BookEJB";
bookEJB = (BookEJB) InitialContext.doLookup(lookupName);
} catch (NamingException e) {
e.printStackTrace();
}
}
#GET
#Produces("application/xml")
#Path("/{bookId}")
public Book getBookById(#PathParam("bookId") Integer id) {
return bookEJB.findById(id);
}
}
See the link below for very useful JNDI look up tips
JNDI look up tips
Arjan is right. I created another class to initialize the EJB instead of creating a bean for RS
#Singleton
#LocalBean
public class Mediator {
#EJB
DatabaseInterface databaseFacade;
to avoid null pointer with:
#Path("stock")
public class StockResource {
#EJB
DatabaseInterface databaseFacade;
...
it actually works on GF
I have the same problem, and I solved it calling te EJB by a context lookup (the injection was impossible, I had the same error NullPointerException).
Related
I have a jar that contains a #Stateless class defined like
#Stateless
public class TestBean() {
#Inject
AnotherBean bean2;
public String getThis() {
return bean2.getAString();
}
}
A webapplication (with a dependency on this jar) running on wildfly 10.1.0 would like to instantiate this bean and use its methods. The webapplication calling method might be a rest endpoint (called by some other webapplication) or just a regular java method.
What is the best way to instantiate TestBean? I have tried several solutions none of which works.
For example this one
Building a CDI 2 standalone
and this one
Does CDI work for regular Java application?
I am new to the CDI and how it works, I am wondering if this is explained well somewhere?
Its not really clear what your question is, but if you have JAX-RS resource, in the WAR file, then this should just work
#Path("/somePath")
#RequestScoped
public class SomeResource {
#Inject
private TestBean testBean;
#GET
public String doGet() {
return testBean.getThis();
}
}
First of all, this is not opinionated question and I have read most of related questions in SO. I am seeking advise if below implemented solution is the right approach/method.
I have read many tutorials on how to implement DI in a jersey-based webapp and most of them recommend that its a must to create a beans.xml in WEB-INF/* in order to enable CDI but, I wonder if using Jersey's AbstractBinder achieve the same result?
I have a jersey-webapp that has the following in web.xml
<servlet>
<servlet-name>Test Jersey</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.test.config.AppConfig</param-value>
</init-param>
And com.test.config.AppConfig as follow
public class AppConfig extends ResourceConfig {
public AppConfig() {
AbstractBinder binder = new AbstractBinder() {
#Override
protected void configure() {
bind(Impl.class).to(Interface.class).in(Singleton.class);
}
};
register(binder);
register(MultiPartFeature.class);
packages("..."); //packages
}
}
and then I annotate the interfaces and the implementation gets injected
#Inject
private SomeInterface someInterface;
Above works just fine. Whatever that I want to be injected, I include it in the binder and then specify an injection point and it gets injected.
There is no beans.xml in WEB-INF/ directory and I wonder if using AbstractBinder inside AppConfig that extends ResourceConfig eliminate the need to declare beans.xml ?
Adding beans.xml would probably enable scanning of classes that would pave the way for DI when we annotate classes with #Component or #ManagedBean.
Regardless, I would be happy to hear your feedback/advise/suggestions/recommendations on whether to
Stick with existing solution (shown above) for DI in Jersey because .... ?
Switch to annotating classes (that needs to be injected) and use annotation-discovery of beans.xml because ... ?
Jersey uses HK2 by default, is it worth using a different DI
container or HK2 is good enough?
What is your view on Jersey's Spring DI in comparison with JavaEE 6
CDI only for DI purposes?
There are many tutorials stating that CDI is not supported by Tomcat? but worked above using AbstractBinder and I guess its because I programmatically bind? Any comments.
I do not have a clear answers and possibly there doesn't exist a correct one. Not least because Weld SE support was introduced in version 2.15 of Jersey and this certainly not without any reason. But I would like to give it a try:
The shown solution works fine for non-complex project structures but declaring every single binding might not be the best solution
You don't need to use beans.xml. Annotations and auto-binding works fine with some additional effort (see below)
I'm not sure about this, but would say Weld seems to be more advanced. And of course you could mix CDI with some effort.
(no answer here)
Here the example, which I think could be interesting:
Dependencies (Maven):
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2-metadata-generator</artifactId>
<version>2.5.0-b05</version> <!-- HK2 version int. used by Jersey 2.23.2 -->
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
</dependency>
An application event listener:
import org.glassfish.hk2.api.*;
import org.glassfish.jersey.server.*;
#Provider
public class ApplicationListener implements ApplicationEventListener {
#Inject ServiceLocator serviceLocator;
#Override
public void onEvent(ApplicationEvent event) {
switch (event.getType()) {
case INITIALIZATION_FINISHED:
onInitFinished();
break;
case DESTROY_FINISHED:
case INITIALIZATION_APP_FINISHED:
case INITIALIZATION_START:
case RELOAD_FINISHED:
default:
break;
}
}
#Override
public RequestEventListener onRequest(RequestEvent requestEvent) { return null; }
public void onInitFinished() {
populate(serviceLocator);
}
private void populate(ServiceLocator serviceLocator) {
DynamicConfigurationService dcs = serviceLocator.getService(DynamicConfigurationService.class);
Populator populator = dcs.getPopulator();
try {
populator.populate();
} catch (IOException | MultiException e) {
throw new MultiException(e);
}
}
}
A contract:
import org.jvnet.hk2.annotations.Contract;
#Contract
public interface ExampleService {
void executeSomething();
}
One or more services:
import javax.inject.Named;
import org.jvnet.hk2.annotations.Service;
#Service
#Named("bar")
public class BarService implements ExampleService {
#Override
public void executeSomething() { /* doBar */ }
}
Usage:
#Path("/")
public class TestResource {
// either ...
#Inject
#Named("bar")
private ExampleService bar;
// or ...
#Inject
private IterableProvider<ExampleService> services;
}
Just an option to get rid of beans.xml (which I've never used or have seen) or declaration within ResourceConfig, but it might find interested parties :)
Additionally, it seems like Jersey 3.0 is comming ^^
Have a nice day!
I do have a EJB ActionService which I can inject into other EJBs, that is working fine.
Now I created another EJB:
#Stateless
public class ActionsPerDateDataSet extends ScriptedDataSetEventAdapter {
#EJB
ActionService actionService;
#Override
public void open(IDataSetInstance dataSet) {
actionService.foo() // However actionService is null here!
}
}
Where the ScriptedDataSetEventAdapter comes from another framework (BIRT).
However now my actionService is always null. I can not understand why
You should introduce the lib as ejbModule in ear file , so that container search the jar file and deploy it and inject it whenever it needs
ActionService has an interface with the #local annotation or if this is a class it has to have the annotation #LocalBean.
(this to be able to access the instance of it at runtime)
In case it is an interface and if it has multiple implementations you will have to reference the implementation you need using #EJB (beanName = "nameOfImplementation") in case it is a class where #LocalBean is used to use #EJB (name = "nameEjb")
Interface with #Local
Class with #LocalBean
In the aggregation class
Interface with multiple implementations #EJB(beanName="nameOfImplementation")
Class #EJB(name="nameEjb")
note: implements an interface for ActionService with #Local and test
note: add trace the console log to know if the class is being initialized as an ejb:ActionService
Did you try using CDI? I think it is worth a shot. You need to place an empty beans.xml inside your meta-inf folder and change #EJB to #Inject. But the only way this could work is if you have the external lib and your war/jar file in the same deployment unit.
if this does not work you will need to use JNDI for looking up your bean:
http://docs.oracle.com/javaee/6/tutorial/doc/gipjf.html
It is possible that the class ScriptedDataSetEventAdapter
can not be initialized in the EJB Container (First part of the cycle)
and as the initialization is not correct, the dependency injection (#EJB and #Inject) is not made.
What you could do is change the Design of your EJB and instead it's extends "ScriptedDataSetEventAdapter"
change it to a composition.
#Stateless
public class ActionsPerDateDataSet {
ScriptedDataSetEventAdapter scriptedDataSetEventAdapter;
#EJB
ActionService actionService;
#PostConstruct
public void init (){
try {
scriptedDataSetEventAdapter = new ScriptedDataSetEventAdapter();
} catch( AppException e){
}
}
#Override
public void open(IDataSetInstance dataSet) {
actionService.foo() // However actionService is null here!
}
}
I'm writing custom JAX-RS 2.0 application (under Jersey 2.3.1) which holds some data for use by all the resources.
public class WebApp extends org.glassfish.jersey.server.ResourceConfig {
public WebApp() {
packages("my.resources.package");
}
}
(I could use API's javax.ws.rs.core.Application as well, the described result is the same)
Then I inject the object into a resource
#Path("test")
public class Test {
#Context
Application app;
#GET
#Path("test")
public String test() {
return "Application class: " + app.getClass();
}
}
However, the result of a call is
Application class: class org.glassfish.jersey.server.ResourceConfig$WrappingResourceConfig
which makes me use some ugly tricks like
if (app instanceof WebApp) {
return (WebApp) app;
} else if (app instanceof ResourceConfig) {
return (WebApp) ((ResourceConfig) app).getApplication();
}
My understanding of JAX-RS 2.0 spec section 9.2.1:
The instance of the application-supplied Application subclass can be injected into a class field or method parameter using the #Context annotation. Access to the Application subclass instance allows configuration information to be centralized in that class. Note that this cannot be injected into the Application subclass itself since this would create a circular dependency.
is that application-supplied Application subclass is mine WebApp, not JAX-RS implementation-specific wrapper.
Also, changing this fragment
#Context
Application app;
to this
#Context
WebApp app;
causes app to be null, due to ClassCastException during context injection, so the declared type doesn't matter.
Is it a bug in Jersey or my misunderstanding?
UPDATE: I checked the behaviour under RESTEasy 3.0. The injected object is my WebApp, without any wrappers. I'd call it a bug in Jersey.
This doesn't seem like a bug. According to JAX-RS 2.0 spec you can inject Application into your resource classes (for example) but it does not say anything about directly injecting custom extensions of the Application. Not sure what your use-case is but you can register custom HK2 binder that will allow you to inject directly WebApp into resources:
public class WebApp extends org.glassfish.jersey.server.ResourceConfig {
public WebApp() {
packages("my.resources.package");
register(new org.glassfish.hk2.utilities.binding.AbstractBinder() {
#Override
protected void configure() {
bind(WebApp.this);
}
});
}
}
I too have encountered this using Jersey 2.4.1.
FWIW: I agree it seems like a bug according to the spec para 8.2.1. The statement "The instance of the application-supplied Application subclass" seems perfectly clear.
I have an alternative workaround that doesn't involve glassfish.hk2 but still concentrates the Jersey-specific code in the Application-derived class.
public class MyApp extends ResourceConfig {
...
static MyApp getInstance( Application application) {
try {
// for a conformant implementation
return (MyApp) application;
} catch (ClassCastException e) {
// Jersey 2.4.1 workaround
ResourceConfig rc = (ResourceConfig) application;
return (MyApp) rc.getApplication();
}
}
...
}
public class MyResource {
...
#Context Application application;
...
SomeMethod() {
... MyApp.getInstance( application);
}
}
Hope this is useful.
This appears to be fixed in a later version og Jersey. The same approach works for me with Jersey 2.16 at least. My injected Application object is of the correct subclass without any wrapping whatsoever.
Edit: Or maybe the version is irrelevant after all. Please see the comments to this answer.
I'm developping simple app where one EJB should be injected into another. I'm developping in IDEA Jetbrains IDE. But after i make #EJB annotation in Ejb local statless class my IDE highlight it with error:
EJB '' with component interface 'ApplicationController' not found.
Can anyone tell Why?
Injection of an EJB reference into another EJB can be done using the #EJB annotation. Here is an example taken from Injection of other EJBs Example from the OpenEJB documentation:
The Code
In this example we develop two simple
session stateless beans (DataReader
and DataStore), and show how we can
use the #EJB annotation in one of
these beans to get the reference to
the other session bean
DataStore session bean
Bean
#Stateless
public class DataStoreImpl implements DataStoreLocal, DataStoreRemote{
public String getData() {
return "42";
}
}
Local business interface
#Local
public interface DataStoreLocal {
public String getData();
}
Remote business interface
#Remote
public interface DataStoreRemote {
public String getData();
}
DataReader session bean
Bean
#Stateless
public class DataReaderImpl implements DataReaderLocal, DataReaderRemote {
#EJB private DataStoreRemote dataStoreRemote;
#EJB private DataStoreLocal dataStoreLocal;
public String readDataFromLocalStore() {
return "LOCAL:"+dataStoreLocal.getData();
}
public String readDataFromRemoteStore() {
return "REMOTE:"+dataStoreRemote.getData();
}
}
Note the usage of the #EJB annotation
on the DataStoreRemote and
DataStoreLocal fields. This is the
minimum required for EJB ref
resolution. If you have two beans that
implement the same business
interfaces, you'll want to the
beanName attribute as follows:
#EJB(beanName = "DataStoreImpl")
private DataStoreRemote dataStoreRemote;
#EJB(beanName = "DataStoreImpl")
private DataStoreLocal dataStoreLocal;
Local business interface
#Local
public interface DataReaderLocal {
public String readDataFromLocalStore();
public String readDataFromRemoteStore();
}
(The remote business interface is not
shown for the sake of brevity).
If it doesn't work as expected, maybe show some code.
I believe it's an IntelliJ IDEA bug. This thread solved the problem for me:
adding a EJB Facet (in project structure > modules) helped