How to Use Jersey as Jax-Rs Implementation Without Web.Xml

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

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

How to implement jaxrs Application without web.xml

You need to deploy your application into a Servlet 3.0 compliant container to take advantage of this functionality. Try GlassFish 3.x or Tomcat 7.

Configure Jersey MVC to serve Viewable without web.xml

Peter Metz, I believe this is possible by using the @WebFilter annotation on a class that extends org.glassfish.jersey.servlet.ServletContainer (Jersey 2.26):-

package com.myorg.myapp.config;

import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;

import org.glassfish.jersey.servlet.ServletContainer;

@WebFilter(value = "/*", initParams = @WebInitParam(name = "javax.ws.rs.Application", value = "com.myorg.myapp.config.JerseyConfig"))
public class JerseyFilter extends ServletContainer {

private static final long serialVersionUID = 1L;

}

Annotation based Spring / JAX-RS integration with no web.xml

You can integrate Spring and Jersey in a XML-less mode.

You will need to extend the class com.sun.jersey.spi.spring.container.servlet.SpringServlet. e.g.:

package org.test;

import com.sun.jersey.spi.spring.container.servlet.SpringServlet;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;

@WebServlet(urlPatterns = {"/rest/*"}, initParams = {
@WebInitParam(name = "com.sun.jersey.config.property.packages",
value = "org.test.rest")})
public class JerseyServlet extends SpringServlet {

}

Actually, it is a servlet. The parameter com.sun.jersey.config.property.packages indicates where scanning the resources (classes with annotation @Path).

The following code is an example of resource:

package org.test.rest;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.test.service.DummyService;

@Path("test")
@Component
public class TestResource {

@Autowired
private DummyService service;

@GET
public String test() {
return service.sayHello();
}

}

Such resources need to be scanned by Spring for dependency injection. e.g.:

package org.test.rest;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("org.test.rest")
public class RestConfiguration {

}

And this configuration can be loaded by the initializer class. e.g.:

package org.test;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import org.test.rest.RestConfiguration;
import org.test.service.ServiceConfiguration;

public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{ServiceConfiguration.class, RestConfiguration.class};
}

@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{};
}

@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}

}

Maybe you want to see the pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.test</groupId>
<artifactId>jersey-spring</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<name>jersey-spring</name>

<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-spring</artifactId>
<version>1.18.3</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>${endorsed.dir}</outputDirectory>
<silent>true</silent>
<artifactItems>
<artifactItem>
<groupId>javax</groupId>
<artifactId>javaee-endorsed-api</artifactId>
<version>7.0</version>
<type>jar</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project>

Could we implement resful webservice via Jersey without manven and web.xml on Tomcat 8

If you have all the jars from the Jersey JAX-RS 2.0 RI bundle, you don't need a web.xml. Just just need an javax.ws.rs.core.Application sublcass, annotated with @ApplicationPath. So this is the most minimal required configuration

@ApplicationPath("/api")
public class MyApplication extends Application {}

Just having this empty class will trigger class-path scanning, which will scan for classes annotated with @Path and @Provider classes.

As mentioned here class-path scanning is not recommended though. Better to use Jersey's package scanning capabilities. First instead of extending Application, you should extend ResourceConfig (which is an Application subclass). Then just call packages("..") to list the package to scan for your resources

@ApplicationPath("/api")
public class AppConfig extends ResourceConfig {
public AppConfig() {
packages("your.packages.to.scan");
}
}

And that's it. You should be up and running, as long as your resource class is structured properly. And make sure all your jars are actually in your WEB-INF/lib when deployed to Tomcat.

See Also:

  • Servlet Based Deployment for other deployment options (information)

Jersey setup without web.xml

Dumb. All I had to do was include the jersey-servlet jar, as prescribed by this answer.

How to set up JAX-RS Application using annotations only (no web.xml)?

It seems that all I needed to do is this (Servlet 3.0 and above)

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/*")
public class MyApplication extends Application {
...
}

And no web.xml configuration was apparently needed (tried on Tomcat 7)

Use ContainerRequestFilter in Jersey without web.xml

I don't think container filters are loaded in as providers. I think you have to set the response filters property. Strangely PackagesResourceConfig doesn't have a setProperty() but you could overload getProperty() and getProperties():

public Object getProperty(String propertyName) {
if(propertyName.equals(ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS)) {
return new String[] {"mycustom.rest.security.SecurityProvider"};
} else {
return super.getProperty(propertyName);
}
}

public Map<String,Object> getProperties() {
propName = ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS;
Map<String,Object> result = super.getProperties();
result.put(propName,getProperty(propName));
return result;
}

Actually, reading the javadocs more closely, it appears the preferred method is:

myConfig.getProperties().put(ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS,
new String [] {"mycustom.rest.security.SecurityProvider"});

Confusion with JAX-RS and Jersey with JAX-RS

JAX-RS specifies a deployment model around Servlets[1]. Why, because in the Java world, that's how web applications are run. Request comes in to a Servlet container (like Tomcat or a container in a full Java EE server), the container hands off the request to the Servlet application, the application processes the request and spits out the response back to the container, which sends it to the client. Spring MVC is a Servlet based framework (main Servlet being DispatcherServlet). JSF is a Servlet based framework (main Servlet is FacesServlet). Same way JAX-RS is build around Servlets (main Servlet is implementation specific; in the case of Jersey it's ServletContainer).

Request comes in to Tomcat, it looks up the servlet mappings, it finds ServletContainer matches the request URL, it wraps the request in a HttpServletRequest and ships it off to the Jersey Servlet. Now Jersey can do with it as it pleases, which is a whole lot of processing; such as processing the request to match your methods[2], deserializing entity bodies, and a whole bunch of other stuff that makes all the magic possible. When it's done processing, it send the response back to the container.

why jersey using a servlet?

I think that is made clear above.

JAX-RS not using a servlet?

Not really sure I really understand what you're asking by this, but JAX-RS specifies other deployment models, but a Servlet environment is the only one with any specific requirement details. Other deployment options, like in an SE environment will be implementation specific[1].

Why using JAX-RS, while we can use a just Servlet

You're basically asking, "Why should I use JAX-RS, when I can implement my own REST framework?". Generally, when there is a framework available, use it. If you feel you can make a better one, then do it.

[1] - See 2.3 Publication

[2] - See 3.7 Matching Requests to Resource Methods



UPDATE

So part of the confusion on part of the OP, was that the tutorial he was going through, didn't specify the a Servlet in a web.xml file, which made the OP think that a "vanilla JAX-RS" (which doesn't exist) was being used, ant not an implementation.

JAX-RS is just a specification, and cannot run without an implementation. Yes there is a javax.ws.rx-api.jar or a javaee-api.jar that has the classes/interfaces/annotations to compile a JAX-RS application, but there is no actual "engine" in this jar. The actual JAX-RS "engine" is in the specific implementation jars.

I haven't watched the complete tutorial, but I assume that it uses one of the above jars, which led the OP to believe that no JAX-RS implementation is used. But in actuality, the Java EE server used (which is Glassfish), internally has the implementation. In the case of Glassfish it's Jersey.

Another point of confusion may have been in the app configuration. Instead of using a web.xml as in the OP's post, there is an Application subclass being used. Something like

@ApplicationPath("/rest")
public class AppConfig extends Application {
...
}

The JAX-RS specification states that when this class with annotation is available, a Servlet should be created with the above fully qualified class name as the Servlet name, and the url mapping the be the value in the @ApplicationPath. So whatever implementation you are using, this behavior should be the same.



Related Topics



Leave a reply



Submit