I'm trying to create and deploy a RESTful Web Service using JAX-RS and deploy it to tomcat. I don't want to use any IDE.
In Tomcat I have the following directory structure inside webapps\
notifire\WEB-INF\
|
---> web.xml
|
---> \classes/Notifier.class
|
---> \lib\javax.ws.rs-api-2.0
my web.xml contains:
<servlet>
<servlet-name>Web Service Servlet</servlet-name>
<servlet-class>javax.ws.rs.core.Application</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Web Service Servlet</servlet-name>
<url-pattern>/webservice/*</url-pattern>
</servlet-mapping>
and the class file Notifier.class was compiled from the file Notifier.java.
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
#Path("notifier")
public class Notifier {
#Context
private UriInfo context;
#GET
#Produces("text/html")
public String getHTML() {
return "<p></p>";
}
}
When I try to access the Web Service at http://localhost:8080/notifire/webservice/notifier I get the following error:
--type Exception report
--message Class javax.ws.rs.core.Application is not a Servlet
--description The server encountered an internal error that prevented it from fulfilling this request.
Any help is appreciated.
You have the wrong class for your Servlet. Not sure why you are not wanting to use an IDE, but there is a maven archetype that will layout your project structure for you using the appropriate classes that the Jersey developers have defined. My web.xml looks like this:
<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>com.pluralsight</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>
I cover all of this in this course here.
I had trouble getting this to work as well. Since you have to use web.xml anyway, the simplest way to get restful web services working is to forget extending javax.ws.rs.core.Application entirely and just specify the context path there. You can still use standard jax-rs annotations to declare the actual web services.
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app
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"
version="3.0"
>
<servlet>
<servlet-name>rest-test</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.domain.mypackage</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name> rest-test</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
Two noteworthy points:
You will need to bundle a REST implementation in your WAR file, since servlet containers don't usually contain one. Since Jersey is the reference implementation for JAX-RS, that's the one I'm using in the servlet-class element above. You can replace this with Apache CXF implementation if you want.
The init-param element tells Jersey which of your packages to search for Java files with web service annotations. Edit this to point to your web services. Note that if you opt to use apache CXF instead of Jersey, the stuff needed in any init-param elements will be different. Someone who knows CXF please post what they would be.
If you're using Maven, just add a dependency to jersey-servlet in the dependencies section of your pom.xml file:
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-servlet</artifactId>
<version>1.18.2</version>
</dependency>
...
</dependencies>
After this, declaring your web services is straight forward using the standard JAX-RS annotations in your Java classes:
package com.domain.mypackage;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.GET;
import javax.ws.rs.MatrixParam;
import javax.ws.rs.Path;
// It's good practice to include a version number in the path so you can have
// multiple versions deployed at once. That way consumers don't need to upgrade
// right away if things are working for them.
#Path("calc/1.0")
public class CalculatorV1_0 {
#GET
#Consumes("text/plain")
#Produces("text/plain")
#Path("addTwoNumbers")
public String add(#MatrixParam("firstNumber") int n1, #MatrixParam("secondNumber") int n2) {
return String.valueOf(n1 + n2);
}
}
This should be all you need. If your Tomcat install is running locally on port 8080 and you deploy your WAR file to the context myContext, going to
http://localhost:8080/myContext/rest/calc/1.0/addTwoNumbers;firstNumber=2;secondNumber=3
...should produce the expected result (5).
Cheers!
* Someone please correct me if you know of a way to a add the Jersey servlet to the context in Tomcat without using web.xml--maybe by using a context or life cycle listener?
Related
I have a maven project that has no code, it just imports 3 projects. Two of them define their servlets in a web.xml, so in this project, I import all classes and define only the servlets I need this way
<web-app>
<servlet>...</servlet>
<servlet-mapping>...</servlet-mapping>
</web-app>
And this works. The third project to import works when run standalone, but I fail to import it and I ask for your help. Its source code is anotated with JAX-RS like:
package org.acme.rest;
#Path("search")
public class MySearch {
#GET
#Path("/{type}/{text}")
#Produces("application/json; charset=UTF-8")
public MyResponse typedSearch(#PathParam("type") String type, #PathParam("text") String text) {
/**/
}
}
This class MySearch has a method that defines an endpoint with parameters. The class is registered in the app class like:
package org.acme.util;
import org.acme.rest;
#ApplicationPath("")
public class SearchApp extends ResourceConfig {
public SearchApp (#Context ServletContext servletContext) {
try {
/* ... */
register(MySearch.class);
/* ... */
} catch (/* ... */){/* ... */}
}
Because of logging, I know that the SearchApp servlet is initiated, and that register() is called. However, the endpoint is not loaded, as I receive only a 404. I don't see any hint on why the endpoint may be ignored.
See my web.xml for reference:
<?xml version="1.0" encoding="UTF-8"?>
<web-app
version="4.0"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns="https://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="https://xmlns.jcp.org/xml/ns/javaee
https://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd">
<display-name>Archetype Created Web Application</display-name>
<!-- some servlet from project 1 -->
<servlet>...</servlet>
<servlet-mapping>...</servlet-mapping>
<!-- some servlet from project 2 -->
<servlet>...</servlet>
<servlet-mapping>...</servlet-mapping>
<!-- special servlet for project 3 -->
<servlet>
<servlet-name>Suggest</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.acme.util</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Search</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
</web-app>
I expect to receive a response from typedSearch method by querying /api/search/sometype/sometext. But it's not working.
I am using
Tomcat 9
Java 1.8
Jersey 2.14. I've tried also 2.38 with same result.
Eclipse 2022-03 (4.23.0)
Can you think of something that can be going wrong? Or how to debug it?
I suspect that register() is silently ignoring the endpoint class for some reason, but I can't tell why.
Thank you!
I am completely new to Jersey and am having trouble with getting it to work.
I first built a project in Eclipse using the Maven archetype for Jersey 2, jersey-quickstart-webapp (or something along those lines).
I then converted that project to a Dynamic Web Application so that I could run it on my Tomcat server on Eclipse.
After doing all of that, I cannot get the 'myresource' URL to work.
'http://localhost:8080/Testing/webapi/myresource' shows nothing.
Web.xml:
<?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>com.personal.Testing.Testing</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>
Resource class:
package com.personal.Testing.Testing;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
/**
* Root resource (exposed at "myresource" path)
*/
#Path("myresource")
public class MyResource {
/**
* Method handling HTTP GET requests. The returned object will be sent
* to the client as "text/plain" media type.
*
* #return String that will be returned as a text/plain response.
*/
#GET
#Produces(MediaType.TEXT_PLAIN)
public String getIt() {
return "Got it!";
}
}
From a tutorial (https://howtodoinjava.com/jersey/jersey2-hello-world-example/#webxml)
"First, run maven to create you war file.
Then hot deploy war file to your tomcat server..."
Then try hitting your URL. Should work just fine.
It seems you may be doing a simple run for the application you created in Eclipse. In that case, the application will not be deployed to you Web Server (Tomcat in your case).
You need to deploy the application as a war in the server for the URL to work.
I am following a simple webservice tutorial and can't seem to interact with the Java code. I suspect my web.xml has an error but I'm not sure. There are no obvious errors and the index.jsp is server without any problems.
So, when I'm running it on the server, it opens index.jsp and I then try the following urls, but I'm getting 'HTTP 404 Errors'
http://localhost:8080/RestApi/ - works, shows html page
http://localhost:8080/RestApi/rest - http 404 error
http://localhost:8080/RestApi/rest/hello - http 404 error
http://localhost:8080/RestApi/rest/hello/somevalue - http 404 error
Here is what i have
Dynamic web project with jersey libs imported.
A note on this - I got an error for class not found and saw that I had to use Glassfish.org... instead of the com.sun one, don't know why, but there ya go.
My web.xml is as follows. No errors.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>RestApi</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<display-name>Rest Web Services App by me</display-name>
<servlet>
<servlet-name>exampleServlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.rest.example</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>exampleServlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
My java class is as follows. No errors.
package com.rest.example;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;
#Path("/hello")
public class HelloWorld {
#GET
#Path("/{param}")
public Response getMsg(#PathParam("param") String msg){
String output = "Welcome to the world of Rest : "+msg;
return Response.status(200).entity(output).build();
}
}
You are using the old Jersey 1.x property
com.sun.jersey.config.property.packages
For Jersey 2.x it should be
jersey.config.server.provider.packages
As a general rule, anything where you see com.sun.jersey is for Jersey 1.x and org.glassfish.jersey is for 2.x.
try:
http://localhost:8080/rest/RestApi/hello
check my case
the rule seems like this: /{url-pattern}/{project}/{path}
I run my case with jetty
another example
the above issue can occur due to following reasons :
First check the name of your application deployed in the webapps folder of the tomcat, whether it is matching your url or not that is giving 404.But in the above case, as it is showing the welcome page, then it is not the concern here.
Check the url pattern mention in the web.xml as it must be the same as in the url you are hitting.
<url-pattern>/rest/*</url-pattern>
Third thing to check is that the path defined in the rest class with #Path annotation.
Check the web.xml for following entries if you are using jersey jars 2.x as suggested above by #Paul Samsotha
<servlet>
<servlet-name>Jersey RESTful 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>com.pizzeria</param-value>
</init-param>
</servlet>
There may be a possibility to get this error when your server has been up without any errors but the context of your application hasn't. You can check it in the logs.For further information please refer this Link ---> 404 error due to SEVERE: Context [/example] startup failed due to previous errors
I am trying to get working a simple JAX RS example, but I am failing to do so.
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:jsp="http://java.sun.com/xml/ns/javaee/jsp" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>PLAYGROUND</display-name>
<servlet-mapping>
<servlet-name>playground.Rest</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
</web-app>
Rest.java
package playground;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;
public class Rest extends Application {
#GET
#Path("hello")
public String helloworld() {
return "Hello World!";
}
}
Accessing http://localhost/{warcontext}/api/hello with the browser (GET) gives me 404 error status
It is probably something very silly but I can't figure out.
Using:
JBoss EAP 6.1.0 (Java EE 6)
web.xml
<servlet>
<servlet-name>RestServlet</servlet-name>
<servlet-class>javax.ws.rs.core.Application</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RestServlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
Rest.java
public class Rest {
#GET
#Path("hello")
public String helloworld() {
return "Hello World!";
}
}
If you need, you can add
YourApplication.java
package playground;
import javax.ws.rs.core.Application;
...
public class YourApplication extends Application {
#Override
public Set<Class<?>> getClasses()
{
Set<Class<?>> yourResources = new HashSet<Class<?>>();
yourResources.add(InvoiceResource.class);
return yourResources;
}
}
Then
web.xml
<servlet>
<servlet-name>RestServlet</servlet-name>
<servlet-class>playground.YourApplication</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RestServlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
If you add #ApplicationPath("/api") for YouApplication, then web.xml shouldn't have servlet-mapping.
You need to extend javax.ws.rs.core.Application (it can remain empty) and annotate it with #ApplicationPath("/ide"), then create a JAX-RS resource, ie, a class with an #Path("/hello") annotation. In this class, you'll just need to have your JAX-RS Resource Method annotated with #GET.
#ApplicationPath("/ide")
public class Rest extends Application { }
#Path("/hello")
public class HelloResource {
#GET
#Path("hello")
public String helloworld() {
return "Hello World!";
}
}
You can also take a look at this example: https://github.com/resteasy/Resteasy/tree/master/jaxrs/examples/oreilly-workbook/ex03_1
You need to declare servlet-class in web.xml (servlet name is not the same):
<servlet>
<servlet-name>Playground REST services</servlet-name>
<servlet-class>your.package.playground.Rest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Playground REST services</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
Use the full name of your class (including package path name) in servlet-class.
I also had issues getting this to work, so I'm posting a more complete how-to for posterity:
If you're using a standard Tomcat install (or some other servlet container), AFAIK you can't avoid explicitly telling it what servlets to start in the web.xml file*. Since you have to use web.xml anyway, the simplest way to get restful web services working is to forget extending javax.ws.rs.core.Application entirely and just specify the context path there. You can still use standard jax-rs annotations to declare the actual web services.
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app
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"
version="3.0"
>
<servlet>
<servlet-name>rest-test</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.domain.mypackage</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name> rest-test</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
Two noteworthy points:
You will need to bundle a REST implementation in your WAR file, since servlet containers don't usually contain one. Since Jersey is the reference implementation for JAX-RS, that's the one I'm using in the servlet-class element above. You can replace this with Apache CXF implementation if you want.
The init-param element tells Jersey which of your packages to search for Java files with web service annotations. Edit this to point to your web services. Note that if you opt to use apache CXF instead of Jersey, the stuff needed in any init-param elements will be different. Someone who knows CXF please post what they would be.
If you're using Maven, just add a dependency to jersey-servlet in the dependencies section of your pom.xml file:
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-servlet</artifactId>
<version>1.18.2</version>
</dependency>
...
</dependencies>
After this, declaring your web services is straight forward using the standard JAX-RS annotations in your Java classes:
package com.domain.mypackage;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.GET;
import javax.ws.rs.MatrixParam;
import javax.ws.rs.Path;
// It's good practice to include a version number in the path so you can have
// multiple versions deployed at once. That way consumers don't need to upgrade
// right away if things are working for them.
#Path("calc/1.0")
public class CalculatorV1_0 {
#GET
#Consumes("text/plain")
#Produces("text/plain")
#Path("addTwoNumbers")
public String add(#MatrixParam("firstNumber") int n1, #MatrixParam("secondNumber") int n2) {
return String.valueOf(n1 + n2);
}
}
This should be all you need. If your Tomcat install is running locally on port 8080 and you deploy your WAR file to the context myContext, going to
http://localhost:8080/myContext/rest/calc/1.0/addTwoNumbers;firstNumber=2;secondNumber=3
...should produce the expected result (5).
Cheers!
* Someone please correct me if you know of a way to a add the Jersey servlet to the context in Tomcat without using web.xml--maybe by using a context or life cycle listener?
I wrote a very simple example using Jersey.
I downloaded the latest jar files from the jersey website into lib folder in WEB-INF.
My class and web.xml are below.
When I provide URL localhost:8080/SimpleJersey/rest/test I get 404 error (not found).
However when I use Maven, it works.
I use Eclipse Kepler, Glassfish 4 server and Java 7.
What am I doing wrong in the non-Maven version?
Thanks.
Class:
package com.simplejersey;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
#Path("/test")
public class MyResources
{
#GET
#Produces("text/plain")
public String getIt()
{
return "Hello there!";
}
}
Web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>SimpleJersey</display-name>
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.simplejersey</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
I found the solution in this post by Michal Gajdos: Jersey REST Web Service, Tomcat, Eclipse and 404's
The issue is (quoting from the abovementioned post):
Jersey 2.0 does not recognize init-param with name com.sun.jersey.config.property.packages (web.xml). Try to change it to jersey.config.server.provider.packages as described in ServerProperties.PROVIDER_PACKAGES (link)."
Be carefeul when you copy web.xml from websites that show older solutions or versions (like I did). Jersey is being updated too...