How to use Jersey as JAX-RS implementation without web.xml? - java

I have read that from JavaEE 6 web.xml is optional.
So without web.xml, how can I tell the application server to use Jersey as the implementation for JAX-RS specification?

What #AlexNevidomsky wrote in his answer is correct, as far as how to implement the app configuration with no web.xml; you use an #ApplicationPath annotation on an Application subclass.
#ApplicationPath("/api")
public class AppConfig extends Application {}
For more information on deployment options, see the Jersey Docs: Chapter 4. Application Deployment and Runtime Environments
Or more commonly, with Jersey as implementation, we would extend ResourceConfig (which extends Application).
#ApplicationPath("api")
public class AppConfig extends ResourceConfig {
public AppConfig() {
packages("package.to.scan");
}
}
So how is this implemented...
First things first, not all Java EE servers use Jersey. Actually the only ones I know that use Jersey are Glassfish and WebLogic. JBoss uses Resteasy. Tom EE uses CXF. WebSphere uses Apache Wink. Those are the only ones I can think of.
So I guess the question is "How does the Server know how to load the JAX-RS application?"
Servlet 3.0 introduced the pluggability mechanism, which makes use of a ServletContainerInitializer. How it works is that when the Server/Servlet container is started, it scans jars for a META-INF/services folder with a file named javax.servlet.ServletContainerInitializer. This file should include one or more fully qualified names of implementations of the ServletContainerInitializer.
This interface has only one method
void onStartup(java.util.Set<java.lang.Class<?>> c, ServletContext ctx)
The Set<Class<?> will be a list of classes, fitting the criteria in the #HandlesTypes annotation on the ServletContainerInitializer implementation. If you look at Jersey's implementation
#HandlesTypes({ Path.class, Provider.class, Application.class, ApplicationPath.class })
public final class JerseyServletContainerInitializer
implements ServletContainerInitializer {
You should notice some familiar annotation classes, as well as the Application.class. All these classes matching the criteria, while scanning, are added to the Set passed to the onStartup method.
If you scan the rest of the source code, you will see all the registration being done with all of those classes.
Resteasy uses
#HandlesTypes({Application.class, Path.class, Provider.class})
public class ResteasyServletInitializer implements ServletContainerInitializer
I won't get into to others.
Some source you can look at...
JerseyServletContainerInitializer source code
ResteasyServletInitializer source code
JAX-RS specs

You don't have to specify anything in web.xml. Define an activator class:
#ApplicationPath("/rest")
public class _JaxRsActivator extends javax.ws.rs.core.Application {
static {
//Check some system init on REST init.
Config.initCheck();
}
}

Related

Convert Grizzly/Jersey to Payara

So, we've built a webapp using Grizzly/Jersey. You run the produced jar file, and it then provides REST endpoints, which allow pulling data from the database and creating new entries, etc. For one reason or another, we now want to migrate to a webserver, like Payara or Glassfish or something. I'm having trouble getting it to work. It compiles to a war, now, and gets deployed to Payara. Following Deploying jersey web services on Payara 4 doesn´t expose methods, I got it to at least acknowledge that there are endpoints. However, they rely on an injected EntityManager, which we define/bind (along with its dependencies) in a ResourceConfig subclass, which isn't getting loaded, so it crashes. Anybody know how to load the ResourceConfig? Also, anything else that will need to be done to get this working?
If you're going off the answer from your linked post
#javax.ws.rs.ApplicationPath("API_PATH_FOR_JAXRS")
public class SampleApplication extends Application {
}
This would explain the behavior you are seeing. An empty Application annotated with #ApplicationPath will cause the Jersey bootstrap to scan the classpath for #Path and #Provider class, and register those classes.
But you are using a ResourceConfig to do all your registration yourself. It just happens that ResourceConfig is actually a subclass of Application. So instead of creating a new Application subclass to put the #ApplicationPath annotation on, just put on your ResourceConfig subclass.
If you were not subclassing ResourceConfig previously, e.g.
ResourceConfig config = new ResourceConfig()
.packages("...")
.register(...);
Then just subclass it now
#ApplicationPath("...")
public class AppConfig extends ResourceConfig {
public AppConfig() {
packages("...");
register(...);
}
}

Jersey and Google Guice integration

My question is: why do I need to create AbstractModule when doing JavaSE application and ServletModule while creating application that is deployed on some kind of servlet container like jetty or tomcat? What are the differences between them?
I need to integrate Jersey with Guice. Is it necessary to register presence of Guice for Jersey to use it somehow? Can't I just enable injections and do them everywhere I want (normal classes, filters, handlers, services, DAOs etc.)? And why can't I just configure guice like in JavaSE application, but instead need to use ServletModule?
As far as I see on web, there are many examples of using HK2 services by Guice and vice versa, so I can consider it as important? (necessary?)
Thanks
An AbstractModule is the basic building block of the bootstrap (configuration) phase of Guice. You always need one or more of that. On the other hand a ServletModule is an specialization which does some configuration for you given the fact that it is running in a servlet container.
From the Guice documentation:
This module sets up the request and session scopes, and provides a
place to configure your filters and servlets from.
About the Guice-Jersey integration you certainly need to set it up. It won't work out of the blue. Guice, as any other dependency injection framework, works when it has the control of building your objects. When in doubt ask yourself who creates the object.
With Jersey, and JAX-RS in general, who creates the objects? Not you, you just define them. The container creates them. The JAX-RS runtime. In your case, the Jersey runtime. And Jersey uses internally the HK2 dependency injection framework. So you need to bridge both those frameworks in order to inject a JAX-RS class you have defined with some Guice resources. Or the other way around! That is the reason why there is a HK2-guice bridge. So Jersey would build your objects using HK2 and HK2 will look up your resources also on Guice thanks to the bridge.
A simple example. I use this code to initialize a REST API where I want to inject Guice resources.
#ApplicationPath("api")
public class ApiRest extends ResourceConfig {
private static final Logger log = LoggerFactory.getLogger(ApiRest.class);
#Inject
public ApiRest(ServiceLocator serviceLocator, ServletContext servletContext) {
log.debug("Inicialitzant Jersey.");
packages("net.sargue.app.api");
GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
Injector injector = (Injector) servletContext.getAttribute(Injector.class.getName());
if (injector == null)
throw new RuntimeException("Guice Injector not found");
guiceBridge.bridgeGuiceInjector(injector);
}
}
Please note that the above example needs the ServletModule registered as it pulls the Guice injector from the ServletContext. Or you can just add the injector to the ServletContext somewhere else. Or just create the injector when initializing the REST API, it depends on your preferences and the application.

What is the equivalent of `transport-guarantee` when I register a Servlet in a BundleActivator without using web.xml?

I am running Servlets in an OSGI environment, specifically, I use Karaf with Pax Web / Jetty.
I was happily using the BundleActivator to instantiate servlets and register them with the HttpService. What I like about it is that it gives me a very straightforward way to handle dependency injection by wiring up a ServiceTracker.
However, for some things I can only find documentation about how to set them up via the classical web.xml configuration. Specifically, I miss an equivalent for the transport-guarantee instruction, i. e. a way to tell the HttpService that on certain URLs, it should insist on HTTPS and redirect the client if necessary.
Alternatively, if I can use the web.xml descriptor file as usual, but still get a convenient and simple way to wire up the servlet to my OSGi services, I would be fine with that.
Right now I'd say it's a web.xml only feature. Might want to open a new Feature Request. Regarding Injection of OSGi services in Servlets. If you combine your application with Pax CDI you are able to inject OSGi services by CDI means.
#WebServlet(urlPatterns = "/myServlet")
public class MyServlet extends HttpServlet {
#Inject
#OsgiService
private AnotherService service;
...

EJB Injection in Application Client don't work

I tried inject a stateless EJB in my application client and I get the following error
SEVERE: Exception while preparing the app : Unable to load the EJB module. DeploymentContext does not contain any EJB. Check the archive to ensure correct packaging for C:\glassfish3\glassfish\domains\domain1\applications\EJB.
If you use EJB component annotations to define the EJB, and an ejb or web deployment descriptor is also used, please make sure that the deployment descriptor references a Java EE 5 or higher version schema, and that the metadata-complete attribute is not set to true, so the component annotations can be processed as expected
My client is defined thus:
#EJB
private static Sless sless;
public static void main(String[] args) {
System.out.println("Sless says: " + sless.hello());
}
The class Sless is my interface which is defined thus:
#Remote
public interface Sless {
public String hello();
}
I also have a class implementing Sless
#Stateless
public class SlessBean implements Sless{
#Override
public String hello() {
return "hello, world!\n";
}
}
Any help as to where the problem is coming from would be appreciated.
1) Standalone clients or non-managed POJOs(POJOs which are not maintained by Containers) do not support annotation injection. So #EJB will not work.
2) You will have to do a manual JNDI look up from your standalone client.
What you need for this ?
1) Your EJB extending Remote interface. Because Local interface does not expose EJB to Cross Application or Remote calls.
2) Dependency jar files in your standalone client. ie: ORB Jar
3) You will need to know RMI/IIOP port on your server.
4) You will also have to take care if Standalone client and Server use different JDK/JRE implementations. For ex: 1 using SUN JDK and other using IBM JDK.
Follow this for connecting to EJB on Glassfish from a Standalone client >> https://glassfish.java.net/javaee5/ejb/EJB_FAQ.html#StandaloneRemoteEJB

How do i access EJB implementing remote interface in separate web application?

I am using Netbeans 6.8 and Glassfish v3.0.
I created an ejb module and created entity classes from database and then created stateless session bean with remote interface. Say eg.
#Remote
public interface customerRemote{
public void add(String name, String address);
public Customer find(Integer id);
}
#Stateless
public class customerBean implements customerRemote{
//implementations of methods
}
Then i created a new web application. But now how do i access remote ejb's in my web application. I could lookup a bean with jndi name but what i want to know is, what type of object it will return? How do i typecast it in customerRemote? I don't have any class named customerRemote in my web application. So, how do i do it? Also, what about the entity class Customer? There is no such class named Customer in my web application also. All ejb's and entity classes are in separate ejb module. Please help me :(
How do i typecast it in
customerRemote? I don't have any class
named customerRemote in my web
application. So, how do i do it? Also,
what about the entity class Customer?
There is no such class named Customer
in my web application also. All ejb's
and entity classes are in separate ejb
module.
Your web application must depend on a library that contains these classes and interfaces. Then you will be able to import the interface and typecast as usual. You have two approaches:
All in one jar. This seems to be what you have now. In this case your web app needs to depend on this jar.
Split API and implementation. A better approach is to split your ejb module in two jars: one jar myModule-api contains the classes that belong to the API of your module. In this case that would be customerRemote and Customer. And another jar myModule-impl contains the implementation (the implementation depends on the API of course). Then in your web app, you only need to depend on the API which is in myModule-api.
I'm using Eclipse 3.5.2, EJB 3.0 and GlassFish 2.1 but I'm sure that this will work for you too.
Well, first of all I have created an EJB project that will be deployed as a stand alone EJB module on the container, and another project that is in fact a web application that uses a single servlet for testing.
I can resolve the same problem adding the next parameters to the #EJB declaration on the servlet that invokes the bean:
public class SimlpeServletClient extends HttpServlet {
.
.
.
#EJB(beanInterface=ISimpleJob.class,mappedName="ISimpleJob")
ISimpleJob statelesBean;
.
.
.
protected void doPost(HttpServletRequest ...){...}
.
.
.
}
And this is the structure of the bean that implements the interface exposed to the servlet:
#Stateless(name="SimpleJobBean", mappedName="ISimpleJob")
#Remote( { ISimpleJob.class })
public class SimpleJobBean implements ISimpleJob {
.
.
.
}
As you can see, it seems like your client only knows the interface to work with, but it doesn't tell the server which resource can fullfill the request.

Categories