Dependency Injection using CDI with Jersey with/without abstract binding - java

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!

Related

Unit testing JAX-RS/Jersey servlet with Guice Injections

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.

EJB no interface view testing (arquillain & mockito)

I am working on a Java EE 7 (on wildfly 9.0.2) application and I stumbled on an article http://www.oracle.com/technetwork/articles/java/intondemand-1444614.html. Mainly about:
Premature Extensibility Is the Root of Some Evil
This makes sense in certain cases I have encountered. I have changed some classes to a no interface view. The implementation itself is not a problem, testing however is.
For example I have these 2 classes.
#Stateless
public class SomeBean {
public String getText()
{
return "Test text";
}
}
And
#Stateless
public class SomeOtherBean {
#Inject
private SomeBean someBean;
public String getText()
{
return someBean.getText();
}
}
I want somehow that the someBean property is overwritten with preferably a mocked object. Without altering the SomeBean and SomeOtherBean class. I have tried some examples, but they didn't work for example:
https://github.com/arquillian/arquillian-showcase/tree/master/extensions/autodiscover/src/test/java/org/jboss/arquillian/showcase/extension/autodiscover
Has anyone encountered this before and have a solution?
I ended up using 2 solutions.
Solution 1: Use mockito for internal or smaller tests
For testing a particular class Mockito is really useful, as it supports dependency injection.
#RunWith(MockitoJUnitRunner.class)
public class SomeOtherBeanTest {
#Mock
private SomeBean someBean;
#InjectMocks
private SomeOtherBean someOhterBean;
#Before
public void setUp() {
Mockito.when(someBean.getText()).thenReturn("Overwritten!");
}
#Test
public void testGetText() throws Exception {
assertEquals("Overwritten!", someOhterBean.getText());
}
}
Solution 2: Use #Produces and #Alternatives for mocking external services (e.g. mocking OAuth2 server) or larger test (e.g. integration testing)
First I create a new #Alternative annotation:
#Alternative
#Stereotype
#Retention(RUNTIME)
#Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
public #interface CDIMock {}
Then add this as stereotype to the arquillian beans.xml deployment:
<?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"
bean-discovery-mode="all">
<alternatives>
<stereotype>com.project.CDIMock</stereotype>
</alternatives>
</beans>
After that create a new #Producer method in a seperate class:
public class SomeBeanMockProducer {
#Produces #CDIMock
public static SomeBean produce() {
SomeBean someBean = Mockito.mock(SomeBean.class);
Mockito.when(someBean.getText()).thenReturn("mocked");
return someBean;
}
}
Add the SomeBeanMockProducer class to the arquillian deployment and you should have it working.
An alternative to this solution is using #Specializes and extending the SomeBean implementation. In my opinion this doesn't give me enough control like the #Alternative + Mocking solution (#CDIMock in my example).
For example, lets say I SomeBean has methods that calls remote servers. If I add a method to this and forget to #override this in the #Specializes class it will make a real remote call, this won't be the case with Mocking.
It is kind of obvious that substituting a Mock or other specialized object for an injected no-interface class is more difficult, since that is exactly what you wanted by not declaring an interface for the bean.
Having said that, if you are not running a CDI container (e.g. doing POJO unit tests) I think using Mockito is the easiest way.
If you want to do it the "pure CDI" way within a container, you can use the Alternative and Specialization mechanisms of CDI, as described in the Java EE 6 tutorial.
#Specializes
public class SomeBeanMock extends SomeBean {
#Overrides
public String getText()
{
return "mock";
}
}
Of course you can only use mocks that subclass the original bean (since you have no interface) and you are limited to the usual visibility rules. Changing/mocking private field or methods would require reflection or bytecode manipulation (which is what Mockito does behind the scenes).

How to access Spring Bean from JerseyTest subclass

Here is my abstract class which starts Jersey with given Spring context:
public abstract class AbstractJerseyTest extends JerseyTest {
public void setUp() throws Exception {
super.setUp();
}
#AfterClass
public void destroy() throws Exception {
tearDown();
}
#Override
protected URI getBaseUri() {
return URI.create("http://localhost:9993");
}
#Override
protected Application configure() {
RestApplication application = new RestApplication();
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
properties.put("contextConfigLocation", "classpath:spring-context-test.xml");
application.setProperties(properties);
application.register(this);
return application;
}
}
So, the problem is that I need to access Spring bean from my test to populate database with some data.
Jersey version is 2.6
Also I found a similar question here
But it's related to Jersey 1.x so it doesn't work for Jersey 2.x
Could anyone point me in the right direction?
Solution was really simple.
I added:
#Autowired
private Repository repository;
to the AbstractJerseyTest and this field was automatically autowired during test startup. I don't know details about how it works, but it seems that when I register instance of the test in REST application
application.register(this);
it automatically autowires all beans in the test.
Normally in your case, I'd just say work with mocks, but there are cases where you may need to expose the services in the test class.
To do this without any "ugly hacks", you will need to get a handle on the ServiceLocator (which is analogous to Spring's ApplicationContext). When the Jersey app boots up, all the Spring services from the ApplicationContext are put into the ServiceLocator through HK2's Spring bridge.
The problem is JerseyTest does not expose the ServiceLocator in any way. The only way I can think of to get a hold of it, is to create your own TestContainerFactory, and create the ApplicationHandler, which exposes the ServiceLocator.
Trying to implement your own TestContainerFactory is not a walk in the park, if you don't know what you're doing. The easiest thing to do is just look at the source code for Jersey's InMemoryTestContainerFactory. If you look at the constructor for the inner class InMemoryTestContainer, you will see it creating the ApplicationHandler. This is how you can expose the ServiceLocator, through the appHandler.getServiceLocator().
So if you copied that class, and exposed the ServiceLocator, you could create your JerseyTest extension, and call the ServiceLocator.inject(Object) method to inject the test class.
public abstract class AbstractServiceLocatorAwareJerseyTest extends JerseyTest {
private final ServiceLocatorAwareInMemoryTestContainerFactory factory
= new ServiceLocatorAwareInMemoryTestContainerFactory();
private ServiceLocator locator;
#Override
public TestContainerFactory getTestContainerFactory() {
return factory;
}
#Before
#Override
public void setUp() throws Exception {
super.setUp();
this.locator = factory.getServiceLocator();
if (injectTestClass()) {
this.locator.inject(this);
}
}
public boolean injectTestClass() {
return true;
}
public ServiceLocator getServiceLocator() {
return locator;
}
}
And if for any reason you needed it, the ServiceLocator also has the ApplicationContext, which you could also expose to your test class if needed.
I put together a GitHub project, with a complete implementation, with tests if you want to take a look at it.
UPDATE
Though the OP's answer to this question works, I believe the fact that it works, is a bug. I originally deleted this answer, after the OP posted their answer, but after some testing, I believe that solution is a bug, so I've undeleted this post for anyone who doesn't like the warning1 you get when you use that solution
1. "WARNING: A provider SimpleTest registered in SERVER runtime does not implement any provider interfaces applicable in the SERVER runtime. Due to constraint configuration problems the provider SimpleTest will be ignored."

JAX-RS Application subclass injection

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.

Inject an EJB into JAX-RS (RESTful service)

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).

Categories