The JAX-RS 1.1 specification says on page 6:
If no Application subclass is present
the added servlet MUST be named:
javax.ws.rs.core.Application
What is the added servlet? Could it be an arbitrary servlet?
If an Application subclass is present
and there is already a servlet defined
that has a servlet initialization
parameter named:
javax.ws.rs.Application
Again, what is "a servlet" here?
If an Application subclass is present
that is not being handled by an
existing servlet then the servlet
added by the ContainerInitializer MUST
be named with the fully qualified name
of the Application subclass.
Does "the servlet added by the ContainerInitializer" mean that the servlets is added automatically? How would a configuration look like?
At the moment I use neither an Application class nor a web.xml and it works (with GlassFish 3.1). Does this deployment mechanism require a full class path scan, which could be slow with big libraries?
How to deploy on a Servlet container?
There is a confusing number of configuration options around in the web. See this example with context params in the web.xml (doesn't work for me!). What is the preferred way to deploy a JAX-RS application?
There are a number of options for deploying into a Java EE 6 container (more specifically a Servlet 3.0 implementation):
The simplest is:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_3_0.xsd" version="3.0">
<servlet>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
Then all the #Path and #Provider classes found in your web application will be available in the "default" JAX-RS application with a servlet URL pattern of "/rest/*".
If you have one or more classes that extends javax.ws.rs.core.Application, you can specify like so:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_3_0.xsd" version="3.0">
<servlet>
<servlet-name>com.example.jaxrs.MyApplication</servlet-name>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>com.example.jaxrs.MyApplication</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
You may want to do the above in case you wish to only return specific sets of #Path/#Provider classes on a URL (so you could have a second MyApplication2 with a different URL pattern above).
You can also skip the whole web.xml altogether and just annotate your MyApplication class wih #ApplicationPath which will serve as the URL pattern. I would recommend keeping the web.xml in any case because you will probably have to add other information about the web application there anyway.
If you're wondering where the servlet-class comes from, it is automatically added in by the environment. You can get an idea by looking at the Servlet 3.0 ServletContext.
With WAS 8.5, I change the web.xml to add:
<servlet>
<servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.tada.rest.RestApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
My RestApplication look like :
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;
public class RestApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> sets = new HashSet<Class<?>>();
sets.add(RestService.class);
return sets;
}
}
My RestService looks like
#Path("/tada")
public class RestService {
#GET
public String getSomething() {
return "tada";
}
}
And I add in the pom.xml the dependency:
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
</dependency>
With Servlet3.0, follow this. This works for me.
<servlet>
<description>JAX-RS Tools Generated - Do not modify</description>
<servlet-name>JAX-RS Servlet</servlet-name>
<servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>your.restsrv.config.RESTConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<enabled>true</enabled>
<async-supported>false</async-supported>
</servlet>
<servlet>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>JAX-RS Servlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
As I said in the comment above, it all depends on the framework you want to use.
http://syrupsucker.blogspot.com/2008/10/deploying-jersey-in-tomcat-60.html for Jersey
http://syrupsucker.blogspot.com/2008/10/deploying-resteasy-in-tomcat-60.html for RESTeasy
As far as I know, JAX-RS does not contain a specification for deployment.
Related
am working on implementing Rest web service and need clarification on the deployment descriptor file. Below is the web.xml code and what I have understood is that whenever the url contains /webapi/ the ServletContainer class gets invoked. Please correct me if am wrong till this point. Further can you tell me what's the significance of the attributes param-name and param-value. Is it that the package mentioned in the param-value is passed as argument to the ServletContainer class?
<?xml version="1.0" encoding="UTF-8"?>
<!-- This web.xml file is not required when using Servlet 3.0 container,
see implementation details http://jersey.java.net/nonav/documentation/latest/jax-rs.html -->
<web-app version="2.5" 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/web-app_2_5.xsd">
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>org.xyz.ws.transporter</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/webapi/*</url-pattern>
</servlet-mapping>
</web-app>
Thanks in advance for your help.
I have understood is that whenever the url contains /webapi/ the ServletContainer class gets invoked.
True.
Further can you tell me what's the significance of the attributes param-name and param-value
init-params are basically just configuration properties that the servlet/filter can use to configure itself.
Here you are configuring a specific property named jersey.config.server.provider.packages, with the value of org.xyz.ws.transporter. Jersey will use the value of the this specific configuration property to set up package scanning. Jersey will scan the package you specify (recursively) for classes annotated with #Provider and #Path. This allows Jersey to register all resources and provider classes.
I have my rest class below.
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
#Path("/users")
public class UserRestService {
#GET
public Response getUser() {
return Response.status(200).entity("getUser is called").build();
}
}
I dont know how does server mapping this /users uri pattern with this UserRestService.java file.Do we need to configure in web configuration...?
My question: How it is invoking UserRestService.java when /users URI pattern is matching?
Thanks in Advance...
Because your jax-ws servlet is set to respond to particular url in your application like a one follows
<servlet>
<servlet-name>jaxws-servlet</servlet-name>
<servlet-class>
com.sun.xml.ws.transport.http.servlet.WSSpringServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>jaxws-servlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
There is a class javax.ws.rs.core.Application; which you need to extend (atleast I did this) in order to register your JaxRs Resource URI and provide the corresponding info in web.xml like :-
public class ExtendedClass extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(UserRestService.class);
return classes;
}
}
in web.xml :-
<servlet>
<description>
JAX-RS Tools Generated - Do not modify</description>
<servlet-name>JAX-RS Servlet</servlet-name>
<servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>package.name.ExtendedClass</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JAX-RS Servlet</servlet-name>
<url-pattern>
/</url-pattern>
</servlet-mapping>
In a REST based architecture everything is a resource. A resource is accessed via a common interface based on the HTTP standard methods (e.g., POST, GET, PUT or DELETE). And it's org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher servlet class mentioned in web.xml of your web application that enlist all JAX-RS root resources and providers.
And with the /* url-pattern all resources will be passed to RESTeasy servlet.
<servlet>
<servlet-name>resteasy-servlet</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>resteasy-servlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
You will be wondering how RESTeasy came to know about my class annotated with #Path, so there is another configuration that let RESTeasy know about your resources which you have to mention in your web.xml i.e.
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
So when request comes from /users then org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher serrvlet identifies the URI path that a resource class or class method will serve requests for and call it which is UserRestService in your case.
Hope it helps :)
I'm just starting out with JavaEE (I'm decently fluent in JavaSE) and am having trouble wrapping my brain around all the new things that are required to make even the simplest of applications. Right now I am trying to use JAX-RS annotations to generate a simple "Hello World" html page in IntelliJ using Glassfish 4. I've searched around for the proper use of these annotations, and it seems like I'm doing it correctly, but I keep getting a 404 no matter where I navigate in localhost. I'm starting to think I'm missing vital components in my code, and I don't know enough about JavaEE to know what I'm missing (perhaps it could be something in the web xml file, which I don't know too much about). Here is the code that I wrote, minus the imports:
#LocalBean
#Stateless
#Path("/hello")
#Produces("text/html")
public class Hello {
#GET
#Path("/world")
public String printHelloWorld() {
return "<html lang=\"en\"><body><h1>Hello, World!</h1></body></html>";
}
}
The server itself is up and running and the application seems to deploy correctly. The default URL that is set up at launch time is "http://localhost:8080/HelloWorld_war_exploded/",
so my understanding is that I should be going to
http://localhost:8080/HelloWorld_war_exploded/hello/world
to display the message.
EDIT: Here is my XML file, which I did not change at all:
<?xml version="1.0" encoding="UTF-8"?>
<web-app 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/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
</web-app>
Upon looking at Lutz's comment, I've investigated the base URL issue and am currently viewing the following link: http://www-01.ibm.com/support/knowledgecenter/SSAW57_8.5.5/com.ibm.websphere.nd.doc/ae/twbs_jaxrs_configwebxml.html?cp=SSAW57_8.5.5%2F1-3-0-28-2-0-1
I will update accordingly.
You need to configure Jersey (the JAX-RS implementation in Glassfish) in your web.xml. You currently only have JSF configuration
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>the.package.where.your.resources.are</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
The <url-mapping> is the base for your Jersey app. So you would use
http://localhost:8080/HelloWorld_war_exploded/api/hello/world
If you want to use Standard JAX-RS configuration, you can do
<servlet>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
This will scan your entire classpath for resources, so you don't need to specify the package, like the previous configuration.
Or you can use Java code
#javax.ws.rs.ApplicationPath("/api")
public class RestApplication extends javax.ws.rs.core.Application {
}
Leaving this class empty will also scan the entire classpath for your resources. Or you can add your classes explicitly
#javax.ws.rs.ApplicationPath("/api")
public class RestApplication extends javax.ws.rs.core.Application {
#Override
public Set<Class<?>> getClasess() {
Set<Class<?>> classes = new HashSet<>();
classes.add(Hello.class);
return classes;
}
}
When do I need to include the following snippet in web.xml in order to activate Jersey?
<servlet>
<servlet-name>Jersey App</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.company.rest</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Is it App. Server dependent if Jersey is activated by default or needs this web.xml entry?
If an App. Server does not require the code above, can I configure the servlet-mapping path, like:
<servlet-mapping>
<servlet-name>Jersey App</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
I am just summarizing the Jersey 2.x docs sent by Bhesh in comment:
Servlet 2.x Container
(Java EE 5, Glassfish 2.x), you need to hook Jersey as a Servlet.
<servlet>
<servlet-name>MyApplication</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
...
</init-param>
</servlet>
...
<servlet-mapping>
<servlet-name>MyApplication</servlet-name>
<url-pattern>/myApp/*</url-pattern>
</servlet-mapping>
or a Servlet Filter:
<filter>
<filter-name>MyApplication</filter-name>
<filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
<init-param>
...
</init-param>
</filter>
...
<filter-mapping>
<filter-name>MyApplication</filter-name>
<url-pattern>/myApp/*</url-pattern>
</filter-mapping>
Servlet 3.x Container
Descriptorless case
(Java EE 6, 7; Glassfish 3, 4)There is no need for web.xml configuration for the simplest case. Instead an custom ResourceConfig class is needed with #ApplicationPath annotation for configuration:
#ApplicationPath("resources")
public class MyApplication extends ResourceConfig {
public MyApplication() {
packages("org.foo.rest;org.bar.rest");
}
}
Configuring with web.xml
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<servlet>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/myresources/*</url-pattern>
</servlet-mapping>
</web-app>
In this case all the root resource classes (the classes annotated with #Path annotation) as well as any providers that are annotated with #Provider annotation packaged with the application will be automatically registered in the JAX-RS application.
I am working on project to upgrade my existing web application which is developed in JAX-RS 1.12 and running in tomcat 7. Now I am upgrading it to JAX-RS2.0. During tomcat server startup my resources are not getting loaded ?
Below are the details.
Added below jars for JAX-RS 2.0
jersey-client-2.0-m07-1
jersey-common-2.0-m07-1
jersey-container-servlet-2.0-m07-1
jersey-container-servlet-core-2.0-m07-1
jersey-server-2.0-m07-1
javax.ws.rs-api-2.0-m10
osgi-resource-locator-1.0.1
javax.inject-2.1.28
javax.inject-1
hk2-utils-2.1.28
hk2-locator-2.1.28
hk2-api-2.1.28
guava-13.0
cglib-2.1.28
asm-all-repackaged-2.1.28
In Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>ConfigLiteJersey2</display-name>
<!-- Jersey Servlet to Support JAXRS Services -->
<servlet>
<servlet-name>ConfigLiteServices</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.core.Application</param-name>
<param-value>com.cisco.config.resource</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ConfigLiteServices</servlet-name>
<url-pattern>/config/*</url-pattern>
</servlet-mapping>
My Resource File
#Path("/configset")
public class ConfigSetResource {
#POST
#Path("/id{configsetid: (/[^/]+?)?}")
#Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public ConfigSetResponse getConfigSet(#PathParam("configsetid") String sConfigSetId) throws Exception {
//Code
}
}
Trying to access my resource API using below URL
ipaddress:8080/ConfigLiteJersey2/config/configset/id
Getting HTTP status 404 Not found.
Looks like I am not giving right servletclass mapping in web.xml. Please share your thoughts on this
If you want Jersey to scan your package for resources, change your param-name to:
<param-name>jersey.config.server.provider.packages</param-name>
I am using Jersey 2.15, and below is working configuration:
<servlet>
<servlet-name>emper</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.le.config.ResourceConfiguration</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.le.exceptions</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>emper</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet>
Great thing that I came to know was, we can register provider class like Global Exception handler. hence com.le.exceptions contain my provider class which implements ExceptionMapper provided by Jersey.
Another thing, We need to create a subclass of org.glassfish.jersey.server.ResourceConfig and register it as our jax-rs application.
If you are using Servlet version 3.0 I would suggest following the example in the jersey manual here: https://jersey.java.net/documentation/latest/deployment.html#deployment.servlet.3.descriptor
Create a class that implements javax.ws.rs.core.Application, say org.foo.rest.ConfigLiteApplication. Then make your web.xml like the following (adapted from the jersey page slightly to match your example):
<web-app>
<servlet>
<servlet-name>org.foo.rest.ConfigLiteApplication</servlet-name>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>org.foo.rest.ConfigLiteApplication</servlet-name>
<url-pattern>/config/*</url-pattern>
</servlet-mapping>
</web-app>
This should work on both JAX-RS 1.1 and JAX-RS 2.0, and should be neutral to the jersey version as you never need to name any jersey classes. The ConfigLiteApplication class should load the resources you want to include, for example adapted from http://tomee.apache.org/examples-trunk/rest-example-with-application/README.html:
#ApplicationPath("/config")
public class ConfigLiteApplication extends Application {
public Set<Class<?>> getClasses() {
return new HashSet<Class<?>>(Arrays.asList(ConfigSetResource.class));
}
}
A modern IDE will likely be able to manage this class for you.
Also, if I were you I would be careful to check this regular expression match if you are hoping to match on /id
#Path("/id{configsetid: (/[^/]+?)?}")
I would consider splitting this up into multiple functions or otherwise working to try and avoid this kind of regex. For example
#POST
#Path("/id")
public ConfigSetResponse getConfigSet() {
return this.getConfigSet(null);
}
#POST
#Path("/id/{configsetid}")
public ConfigSetResponse getConfigSet(#PathParam("configsetid") String sConfigSetId) {
//Code
}
After long Google search, I Configured mine this way and it worked perfectly
build.gradle should be something like this
compile 'log4j:log4j:1.2.7'
compile 'org.slf4j:slf4j-log4j12:1.6.6'
compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.6'
ApplicationConfig.java file should be something like this
#ApplicationPath("/app")
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
packages("com.flexisaf.resources");
}
}
Your web.xml file should be something like this
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 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/web-app_3_0.xsd">
<!-- Default page to serve -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<display-name>SAFHRMS</display-name>
<servlet>
<servlet-name>com.flexisaf.safhrms.client.config.ApplicationConfig</servlet-name>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>com.flexisaf.safhrms.client.config.ApplicationConfig</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>safhrms.jsp</welcome-file>
</welcome-file-list>
</web-app>
This solves my problems..Thanks